Package com.caucho.ejb.cfg

Source Code of com.caucho.ejb.cfg.EjbBean

/*
* Copyright (c) 1998-2010 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT.  See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
*   Free Software Foundation, Inc.
*   59 Temple Place, Suite 330
*   Boston, MA 02111-1307  USA
*
* @author Scott Ferguson
*/

package com.caucho.ejb.cfg;

import com.caucho.bytecode.*;
import com.caucho.config.gen.ApiClass;
import com.caucho.config.gen.ApiMethod;
import com.caucho.config.gen.BeanGenerator;
import com.caucho.config.gen.BusinessMethodGenerator;
import com.caucho.config.gen.View;
import com.caucho.config.inject.InjectManager;
import com.caucho.config.program.ConfigProgram;
import com.caucho.config.program.ContainerProgram;
import com.caucho.config.ConfigException;
import com.caucho.config.LineConfigException;
import com.caucho.config.DependencyBean;
import com.caucho.config.types.*;
import com.caucho.ejb.manager.EjbContainer;
import com.caucho.ejb.server.AbstractServer;
import com.caucho.java.gen.CallChain;
import com.caucho.java.gen.GenClass;
import com.caucho.java.gen.JavaClassGenerator;
import com.caucho.loader.EnvironmentBean;
import com.caucho.loader.EnvironmentLocal;
import com.caucho.make.ClassDependency;
import com.caucho.util.L10N;
import com.caucho.vfs.Depend;
import com.caucho.vfs.Path;
import com.caucho.vfs.PersistentDependency;
import com.caucho.vfs.Vfs;

import java.lang.annotation.Annotation;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.lang.reflect.*;

import javax.annotation.PostConstruct;
import javax.ejb.*;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.InjectionTarget;
import javax.interceptor.*;

/**
* Configuration for an ejb bean.
*/
public class EjbBean extends DescriptionGroupConfig
  implements EnvironmentBean, DependencyBean
{
  private static final Logger log = Logger.getLogger(EjbBean.class.getName());
  private static final L10N L = new L10N(EjbBean.class);

  private static EnvironmentLocal<Map<Class,SoftReference<ApiMethod[]>>> _methodCache
    = new EnvironmentLocal<Map<Class,SoftReference<ApiMethod[]>>>();

  private final EjbConfig _ejbConfig;
  private final String _ejbModuleName;

  private ClassLoader _loader;

  protected ClassLoader _jClassLoader;

  private String _ejbName;

  private AnnotatedType _annotatedType;

  // The published name as used by IIOP, Hessian, and
  // jndi-remote-prefix/jndi-local-prefix
  private String _mappedName;

  private String _location = "";
  private String _filename;
  private int _line;
 
  private boolean _isInit; // used for error messsage line #

  // these classes are loaded with the parent (configuration) loader, not
  // the server loader
  private ApiClass _ejbClass;

  private InjectionTarget _injectionTarget;

  protected ApiClass _remoteHome;
 
  protected ArrayList<ApiClass> _remoteList = new ArrayList<ApiClass>();

  protected ApiClass _localHome;
 
  protected ArrayList<ApiClass> _localList = new ArrayList<ApiClass>();

  protected BeanGenerator _bean;

  private boolean _isAllowPOJO = true;

  protected boolean _isContainerTransaction = true;

  ArrayList<PersistentDependency> _dependList
    = new ArrayList<PersistentDependency>();

  ArrayList<PersistentDependency> _configDependList
    = new ArrayList<PersistentDependency>();

  ArrayList<String> _beanDependList = new ArrayList<String>();

  protected ArrayList<EjbMethodPattern> _methodList
    = new ArrayList<EjbMethodPattern>();

  private HashMap<String,EjbBaseMethod> _methodMap
    = new HashMap<String,EjbBaseMethod>();

  private ContainerProgram _initProgram;
  private ArrayList<ConfigProgram> _postConstructList
    = new ArrayList<ConfigProgram>();
  private ContainerProgram _serverProgram;

  private ArrayList<Interceptor> _interceptors
    = new ArrayList<Interceptor>();

  private String _aroundInvokeMethodName;
  private Method _aroundInvokeMethod;
  private String _timeoutMethodName;

  private long _transactionTimeout;

  private AroundInvokeConfig _aroundInvokeConfig;

  private ArrayList<RemoveMethod> _removeMethods
    = new ArrayList<RemoveMethod>();

  /**
   * Creates a new entity bean configuration.
   */
  public EjbBean(EjbConfig ejbConfig, String ejbModuleName)
  {
    _ejbConfig = ejbConfig;
    _ejbModuleName = ejbModuleName;

    _loader = ejbConfig.getEjbContainer().getClassLoader();
  }

  /**
   * Creates a new entity bean configuration.
   */
  public EjbBean(EjbConfig ejbConfig,
     AnnotatedType annType,
     String ejbModuleName)
  {
    _ejbConfig = ejbConfig;

    _annotatedType = annType;
    _ejbModuleName = ejbModuleName;

    setEJBClass(annType.getJavaClass());

    _loader = ejbConfig.getEjbContainer().getClassLoader();
  }

  public EjbConfig getConfig()
  {
    return _ejbConfig;
  }

  public EjbContainer getEjbContainer()
  {
    return _ejbConfig.getEjbContainer();
  }

  public String getAroundInvokeMethodName()
  {
    return _aroundInvokeMethodName;
  }

  public void setAroundInvokeMethodName(String aroundInvokeMethodName)
  {
    _aroundInvokeMethodName = aroundInvokeMethodName;
  }

  public void setAroundInvoke(AroundInvokeConfig aroundInvoke)
  {
    _aroundInvokeConfig = aroundInvoke;

    // ejb/0fbb
    _aroundInvokeMethodName = aroundInvoke.getMethodName();
  }

  public void setInjectionTarget(InjectionTarget injectTarget)
  {
    _injectionTarget = injectTarget;
  }

  public InjectionTarget getInjectionTarget()
  {
    return _injectionTarget;
  }

  /**
   * Returns the remove-method for the given method.
   */
  public RemoveMethod getRemoveMethod(Method method)
  {
    for (RemoveMethod removeMethod : _removeMethods) {
      if (removeMethod.isMatch(method))
        return removeMethod;
    }

    return null;
  }

  /**
   * Returns the remove-method list.
   */
  public ArrayList<RemoveMethod> getRemoveMethods()
  {
    return _removeMethods;
  }

  /**
   * Returns the timeout method name.
   */
  public String getTimeoutMethodName()
  {
    return _timeoutMethodName;
  }

  /**
   * Adds a new remove-method
   */
  public void addRemoveMethod(RemoveMethod removeMethod)
  {
    _removeMethods.add(removeMethod);
  }

  /**
   * Returns the interceptors.
   */
  public ArrayList<Interceptor> getInterceptors()
  {
    return _interceptors;
  }

  /**
   * Returns the interceptors.
   */
  public ArrayList<Interceptor> getInvokeInterceptors(String methodName)
  {
    ArrayList<Interceptor> matchList = null;

    for (Interceptor interceptor : _interceptors) {
      if (methodName.equals(interceptor.getAroundInvokeMethodName())) {
        if (matchList == null)
          matchList = new ArrayList<Interceptor>();

        matchList.add(interceptor);
      }
    }

    return matchList;
  }

  /**
   * Adds a new interceptor.
   */
  public void addInterceptor(Interceptor interceptor)
  {
    _interceptors.add(interceptor);
  }

  /**
   * Returns true if the interceptor is already configured.
   */
  public boolean containsInterceptor(String interceptorClassName)
  {
    return getInterceptor(interceptorClassName) != null;
  }

  /**
   * Returns the interceptor for a given class name.
   */
  public Interceptor getInterceptor(String interceptorClassName)
  {
    for (Interceptor interceptor : _interceptors) {
      String className = interceptor.getInterceptorClass();

      if (className.equals(interceptorClassName))
        return interceptor;
    }

    return null;
  }

  public String getEJBModuleName()
  {
    return _ejbModuleName;
  }

  /**
   * Returns the class loader.
   */
  public ClassLoader getClassLoader()
  {
    return _loader;
  }

  protected Class loadClass(String className)
  {
    try {
      return Class.forName(className, false, _loader);
    } catch (ClassNotFoundException e) {
      throw ConfigException.create(e);
    }
  }

  /**
   * Sets the location
   */
  public void setConfigLocation(String filename, int line)
  {
    if (_filename == null) {
      _filename = filename;
      _line = line;
    }

    if (_location == null)
      _location = filename + ":" + line + ": ";
  }

  /**
   * Sets the location
   */
  public void setLocation(String location)
  {
    _location = location;
  }

  /**
   * Gets the location
   */
  public String getLocation()
  {
    return _location;
  }

  /**
   * Gets the file name
   */
  public String getFilename()
  {
    return _filename;
  }

  /**
   * Gets the line
   */
  public int getLine()
  {
    return _line;
  }

  /**
   * Sets true if POJO are allowed.
   */
  public void setAllowPOJO(boolean allowPOJO)
  {
    _isAllowPOJO = allowPOJO;
  }

  /**
   * Return true if POJO are allowed.
   */
  public boolean isAllowPOJO()
  {
    return _isAllowPOJO;
  }

  /**
   * Sets the ejbName
   */
  public void setEJBName(String ejbName)
  {
    _ejbName = ejbName;
  }

  /**
   * Gets the ejbName
   */
  public String getEJBName()
  {
    return _ejbName;
  }

  /**
   * The mapped-name is the remote published name
   * used by IIOP, Hessian, and jndi-remote-prefix, jndi-local-prefix.
   * The default is the EJBName.
   */
  public void setMappedName(String mappedName)
  {
    _mappedName = mappedName;
  }

  /**
   * The mapped-name is the published name
   * used by IIOP, Hessian, and jndi-remote-prefix, jndi-local-prefix.
   */
  public String getMappedName()
  {
    return _mappedName == null ? getEJBName() : _mappedName;
  }

  /**
   * Returns the kind of bean.
   */
  public String getEJBKind()
  {
    return "unknown";
  }

  /**
   * Sets the ejb implementation class.
   */
  public void setEJBClass(Class ejbClass)
    throws ConfigException
  {
    setEJBClassWrapper(new ApiClass(ejbClass, _annotatedType));
  }

  /**
   * Sets the ejb implementation class.
   */
  public void setEJBClassWrapper(ApiClass ejbClass)
    throws ConfigException
  {
    if (_ejbClass != null && ! _ejbClass.getName().equals(ejbClass.getName()))
      throw error(L.l("ejb-class '{0}' cannot be redefined.  Old value is '{1}'.",
                      _ejbClass.getName(), ejbClass.getName()));


    _ejbClass = ejbClass;

    if (! _ejbClass.isPublic())
      throw error(L.l("'{0}' must be public.  Bean implementations must be public.", ejbClass.getName()));

    if (_ejbClass.isFinal())
      throw error(L.l("'{0}' must not be final.  Bean implementations must not be final.", ejbClass.getName()));

    if (_ejbClass.isInterface())
      throw error(L.l("'{0}' must not be an interface.  Bean implementations must be classes.", ejbClass.getName()));

    // ejb/02e5
    Constructor constructor = null;
    try {
      constructor = ejbClass.getConstructor(new Class[0]);
    } catch (Exception e) {
      log.log(Level.FINE, e.toString(), e);
    }

    if (constructor == null)
      throw error(L.l("'{0}' needs a public zero-arg constructor.  Bean implementations need a public zero-argument constructor.", ejbClass.getName()));

    for (Class exn : constructor.getExceptionTypes()) {
      if (! RuntimeException.class.isAssignableFrom(exn)) {
        throw error(L.l("{0}: constructor must not throw '{1}'.  Bean constructors must not throw checked exceptions.", ejbClass.getName(), exn.getName()));
      }
    }

    ApiMethod method = ejbClass.getMethod("finalize", new Class[0]);

    if (method != null
  && ! method.getMethod().getDeclaringClass().equals(Object.class)) {
      throw error(L.l("'{0}' may not implement finalize().  Bean implementations may not implement finalize().", method.getMethod().getDeclaringClass().getName()));
    }

    if (_annotatedType == null) {
      InjectManager manager = InjectManager.create();

      _annotatedType = manager.createAnnotatedType(_ejbClass.getJavaClass());
    }
  }

  /**
   * Gets the ejb implementation class.
   */
  public Class getEJBClass()
  {
    try {
      if (_ejbClass == null)
        return null;

      return Class.forName(_ejbClass.getName(), false, getClassLoader());
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      throw ConfigException.create(e);
    }
  }

  /**
   * Gets the ejb implementation class.
   */
  public ApiClass getEJBClassWrapper()
  {
    return _ejbClass;
  }

  public AnnotatedType getAnnotatedType()
  {
    return _annotatedType;
  }

  /**
   * Gets the ejb implementation class.
   */
  public String getEJBFullClassName()
  {
    return _ejbClass.getName();
  }

  /**
   * Gets the ejb implementation class.
   */
  public String getEJBClassName()
  {
    String s = _ejbClass.getName();
    int p = s.lastIndexOf('.');

    if (p > 0)
      return s.substring(p + 1);
    else
      return s;
  }

  /**
   * Gets the implementation class name.
   */
  public String getFullImplName()
  {
    return getEJBFullClassName();
  }

  /**
   * Sets the remote home interface class.
   */
  public void setHome(Class homeClass)
    throws ConfigException
  {
    ApiClass home = new ApiClass(homeClass);
   
    setRemoteHomeWrapper(home);
  }

  /**
   * Sets the remote home interface class.
   */
  public void setRemoteHomeWrapper(ApiClass remoteHome)
    throws ConfigException
  {
    _remoteHome = remoteHome;

    if (! remoteHome.isPublic())
      throw error(L.l("'{0}' must be public.  <home> interfaces must be public.", remoteHome.getName()));

    if (! remoteHome.isInterface())
      throw error(L.l("'{0}' must be an interface. <home> interfaces must be interfaces.", remoteHome.getName()));

    if (EJBHome.class.isAssignableFrom(remoteHome.getJavaClass())) {
    }
    else if (! isAllowPOJO()) {
      // XXX: does descriptor still have this requirement?
      // i.e. annotations act differently
      throw new ConfigException(L.l("'{0}' must extend EJBHome.  <home> interfaces must extend javax.ejb.EJBHome.", remoteHome.getName()));
    }
  }

  /**
   * Gets the ejb implementation class.
   */
  public ApiClass getRemoteHome()
  {
    return _remoteHome;
  }

  /**
   * Gets the remote home class.
   */
  public Class getRemoteHomeClass()
  {
    if (_remoteHome == null)
      return null;

    try {
      return Class.forName(_remoteHome.getName(), false, getClassLoader());
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Sets the ejb remote interface
   */
  public void setRemote(Class remote)
    throws ConfigException
  {
    setRemoteWrapper(new ApiClass(remote));
  }

  /**
   * Sets the remote interface class.
   */
  public void setRemoteWrapper(ApiClass remote)
    throws ConfigException
  {
    if (! remote.isPublic())
      throw error(L.l("'{0}' must be public.  <remote> interfaces must be public.", remote.getName()));

    if (! remote.isInterface())
      throw error(L.l("'{0}' must be an interface. <remote> interfaces must be interfaces.", remote.getName()));

    if (! EJBObject.class.isAssignableFrom(remote.getJavaClass())
  && ! isAllowPOJO())
      throw new ConfigException(L.l("'{0}' must extend EJBObject.  <remote> interfaces must extend javax.ejb.EJBObject.", remote.getName()));

    if (! _remoteList.contains(remote)) {
      _remoteList.add(remote);
    }
  }

  /**
   * Adds a remote interface class
   */
  public void addBusinessRemote(Class remoteClass)
  {
    ApiClass remote = new ApiClass(remoteClass);
   
    if (! remote.isPublic())
      throw error(L.l("'{0}' must be public.  <business-remote> interfaces must be public.", remote.getName()));

    if (! remote.isInterface())
      throw error(L.l("'{0}' must be an interface. <business-remote> interfaces must be interfaces.", remote.getName()));

    if (! _remoteList.contains(remote)) {
      _remoteList.add(remote);
    }
  }

  /**
   * Gets the remote interface class.
   */
  public ArrayList<ApiClass> getRemoteList()
  {
    return _remoteList;
  }

  /**
   * Gets the remote class.
   */
  public Class getRemoteClass()
  {
    if (_remoteList.size() < 1)
      return null;

    try {
      ApiClass remote = _remoteList.get(0);

      return Class.forName(remote.getName(), false, getClassLoader());
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Sets the ejb local home interface
   */
  public void setLocalHome(Class localHomeClass)
    throws ConfigException
  {
    ApiClass localHome = new ApiClass(localHomeClass);
   
    setLocalHomeWrapper(localHome);
  }

  /**
   * Sets the local home interface class.
   */
  public void setLocalHomeWrapper(ApiClass localHome)
    throws ConfigException
  {
    _localHome = localHome;

    if (! localHome.isPublic())
      throw error(L.l("'{0}' must be public.  <local-home> interfaces must be public.", localHome.getName()));

    if (! localHome.isInterface())
      throw error(L.l("'{0}' must be an interface. <local-home> interfaces must be interfaces.", localHome.getName()));

    if (! EJBLocalHome.class.isAssignableFrom(localHome.getJavaClass())
  && ! isAllowPOJO())
      throw new ConfigException(L.l("'{0}' must extend EJBLocalHome.  <local-home> interfaces must extend javax.ejb.EJBLocalHome.", localHome.getName()));

  }

  /**
   * Gets the local home interface class.
   */
  public ApiClass getLocalHome()
  {
    return _localHome;
  }

  /**
   * Sets the ejb local interface
   */
  public void setLocal(Class local)
    throws ConfigException
  {
    setLocalWrapper(new ApiClass(local));
  }

  /**
   * Sets the local interface class.
   */
  public void setLocalWrapper(ApiClass local)
    throws ConfigException
  {
    if (! local.isPublic())
      throw error(L.l("'{0}' must be public.  <local> interfaces must be public.", local.getName()));

    if (! local.isInterface())
      throw error(L.l("'{0}' must be an interface. <local> interfaces must be interfaces.", local.getName()));

    /*
    if (EJBLocalObject.class.isAssignableFrom(local.getJavaClass())) {
    }
    else if (! isAllowPOJO())
      throw new ConfigException(L.l("'{0}' must extend EJBLocalObject.  <local> interfaces must extend javax.ejb.EJBLocalObject.", local.getName()));
    */

    if (! _localList.contains(local)) {
      _localList.add(local);
    }
  }

  /**
   * Adds a local interface class
   */
  public void addBusinessLocal(Class localClass)
  {
    ApiClass local = new ApiClass(localClass);
   
    if (! local.isPublic())
      throw error(L.l("'{0}' must be public.  <local> interfaces must be public.", local.getName()));

    if (! local.isInterface())
      throw error(L.l("'{0}' must be an interface. <local> interfaces must be interfaces.", local.getName()));

    if (! _localList.contains(local)) {
      _localList.add(local);
    }
  }

  /**
   * Gets the local interface class.
   */
  public ArrayList<ApiClass> getLocalList()
  {
    return _localList;
  }

  /**
   * Returns true if the transaction type is container.
   */
  public boolean isContainerTransaction()
  {
    return _isContainerTransaction;
  }

  /**
   * Returns true if the transaction type is container.
   */
  public void setContainerTransaction(boolean isContainerTransaction)
  {
    _isContainerTransaction = isContainerTransaction;
  }

  /**
   * Adds a method.
   */
  public EjbMethodPattern createMethod(MethodSignature sig)
  {
    for (int i = 0; i < _methodList.size(); i++) {
      EjbMethodPattern method = _methodList.get(i);

      if (method.getSignature().equals(sig))
        return method;
    }

    EjbMethodPattern method = new EjbMethodPattern(this, sig);

    _methodList.add(method);

    return method;
  }

  /**
   * Adds a method.
   */
  public void addMethod(EjbMethodPattern method)
  {
    _methodList.add(method);
  }

  /**
   * Gets the best method.
   */
  public EjbMethodPattern getMethodPattern(ApiMethod method, String intf)
  {
    EjbMethodPattern bestMethod = null;
    int bestCost = -1;

    for (int i = 0; i < _methodList.size(); i++) {
      EjbMethodPattern ejbMethod = _methodList.get(i);
      MethodSignature sig = ejbMethod.getSignature();

      if (sig.isMatch(method, intf) && bestCost < sig.getCost()) {
        bestMethod = ejbMethod;
        bestCost = sig.getCost();
      }
    }

    return bestMethod;
  }

  /**
   * returns the method list.
   */
  public ArrayList<EjbMethodPattern> getMethodList()
  {
    return _methodList;
  }

  /**
   * Sets the transaction timeout.
   */
  public void setTransactionTimeout(Period timeout)
  {
    _transactionTimeout = timeout.getPeriod();
  }

  /**
   * Gets the transaction timeout.
   */
  public long getTransactionTimeout()
  {
    return _transactionTimeout;
  }

  public MessageDestinationRef createMessageDestinationRef()
  {
    return new MessageDestinationRef(Vfs.lookup(_ejbModuleName));
  }
  /**
   * Sets the security identity
   */
  public void setSecurityIdentity(EjbSecurityIdentity securityIdentity)
  {
  }

  /**
   * Adds a list of dependencies.
   */
  public void addDependencyList(ArrayList<PersistentDependency> dependList)
  {
    for (int i = 0; dependList != null && i < dependList.size(); i++) {
      addDependency(dependList.get(i));
    }
  }

  /**
   * Add a dependency.
   */
  public void addDepend(Path path)
  {
    addDependency(new Depend(path));
  }

  /**
   * Add a dependency.
   */
  public void addDependency(PersistentDependency depend)
  {
    if (! _dependList.contains(depend))
      _dependList.add(depend);
  }

  /**
   * Add a dependency.
   */
  public void addDependency(Class cl)
  {
    addDependency(new ClassDependency(cl));
  }

  /**
   * Gets the depend list.
   */
  public ArrayList<PersistentDependency> getDependList()
  {
    return _dependList;
  }

  /**
   * Add a bean dependency.
   */
  public void addBeanDependency(String ejbName)
  {
    if (! _beanDependList.contains(ejbName))
      _beanDependList.add(ejbName);
  }

  /**
   * Gets the bean depend list.
   */
  public ArrayList<String> getBeanDependList()
  {
    return _beanDependList;
  }

  /**
   * Adds an init program.
   */
  public void addInitProgram(ConfigProgram init)
  {
    if (_initProgram == null)
      _initProgram = new ContainerProgram();

    _initProgram.addProgram(init);
  }

  /**
   * Adds an undefined value, e.g. env-entry
   */
  public void addBuilderProgram(ConfigProgram init)
  {
    if (_serverProgram == null)
      _serverProgram = new ContainerProgram();

    _serverProgram.addProgram(init);
  }

  public void setInit(ContainerProgram init)
  {
    if (_initProgram == null)
      _initProgram = new ContainerProgram();

    _initProgram.addProgram(init);
  }

  public void addPostConstruct(PostConstructType postConstruct)
  {
    _postConstructList.add(postConstruct.getProgram(getEJBClass()));
  }

  /**
   * Gets the init program.
   */
  public ContainerProgram getInitProgram()
  {
    if (_postConstructList != null) {
      if (_initProgram == null)
        _initProgram = new ContainerProgram();

      for (ConfigProgram program : _postConstructList)
        _initProgram.addProgram(program);

      _postConstructList = null;
    }

    return _initProgram;
  }

  /**
   * Gets the server program.
   */
  public ContainerProgram getServerProgram()
  {
    return _serverProgram;
  }

  /**
   * Configure initialization.
   */
  @PostConstruct
  public void init()
    throws ConfigException
  {
    try {
      if (_isInit)
        return;
      _isInit = true;

      if (getEJBClassWrapper() == null)
  throw error(L.l("ejb-class is not defined for '{0}'",
      getEJBName()));

      for (EjbMethodPattern methodPattern : _methodList) {
  for (ApiClass localList : _localList) {
    for (ApiMethod apiMethod : localList.getMethods()) {
      methodPattern.configure(apiMethod);
    }
  }
 
  for (ApiClass remoteList : _remoteList) {
    for (ApiMethod apiMethod : remoteList.getMethods()) {
      methodPattern.configure(apiMethod);
    }
  }
      }

      /*
      if (getLocalHome() != null)
  _bean.setLocalHome(getLocalHome());

      for (ApiClass localApi : _localList) {
  _bean.addLocal(localApi);
      }

      if (getRemoteHome() != null)
  _bean.setRemoteHome(getRemoteHome());

      for (ApiClass remoteApi : _remoteList) {
  _bean.addRemote(remoteApi);
      }
      */

      // XXX: add local api

      introspect();

      initIntrospect();
     
      _bean = createBeanGenerator();
     
      if (_bean == null)
        throw new NullPointerException(getClass().getName() + ": createBeanGenerator returns null");

      _bean.introspect();

      _bean.createViews();

      InterceptorBinding interceptor
  = getConfig().getInterceptorBinding(getEJBName(), false);

      if (_aroundInvokeMethodName != null) {
  ApiMethod method = getMethod(_aroundInvokeMethodName,
             new Class[] { InvocationContext.class });

  if (method == null)
    throw error(L.l("'{0}' is an unknown around-invoke method",
        _aroundInvokeMethodName));
 
  // XXX: _bean.setAroundInvokeMethod(method.getMethod());
      }

      /* XXX:
      if (interceptor != null) {
  for (Class cl : interceptor.getInterceptors()) {
    _bean.addInterceptor(cl);
  }
      }
      */

      /*
      if (_interceptors != null) {
        for (Interceptor i : _interceptors) {
          _bean.addInterceptor(i.getInterceptorJClass().getJavaClass());
        }
      }
      */

      for (View view : _bean.getViews()) {
    /*
  for (BusinessMethodGenerator bizMethod : view.getMethods()) {
    if (! isContainerTransaction())
      bizMethod.getXa().setContainerManaged(false);
  }
    */
      }

      /*
      for (EjbMethodPattern method : _methodList) {
  method.configure(_bean);
      }
      */

      for (RemoveMethod method : _removeMethods) {
  method.configure(_bean);
      }

      // assembleBeanMethods();

      // createViews();
    } catch (ConfigException e) {
      throw ConfigException.createLine(_location, e);
    }
  }

  protected void introspect()
  {
    // _bean.introspect();
  }
 
  /**
   * Creates the BeanGenerator generator instance
   */
  protected BeanGenerator createBeanGenerator()
  {
    throw new UnsupportedOperationException(getClass().getName());
  }

  /**
   * Configure initialization.
   */
  public void initIntrospect()
    throws ConfigException
  {
    boolean isExcludeDefault = false;

    // XXX: ejb/0f78
    /*
    if (_ejbClass != null) {
      Interceptors interceptorsAnn = _ejbClass.getAnnotation(Interceptors.class);

      if (interceptorsAnn != null) {
        for (Class cl : interceptorsAnn.value()) {
          // XXX: ejb/0fb0
          if (! containsInterceptor(cl.getName())) {
            addInterceptor(configureInterceptor(cl));
          }
        }
      }

      // ejb/0fbj
      if (_ejbClass.isAnnotationPresent(ExcludeDefaultInterceptors.class))
        isExcludeDefault = true;
    }
    */

    // ejb/0fb5
    InterceptorBinding binding =
      _ejbConfig.getInterceptorBinding(getEJBName(), isExcludeDefault);


    if (binding != null) {
      ArrayList<String> interceptorClasses = new ArrayList<String>();

      for (Class iClass : binding.getInterceptors()) {
        interceptorClasses.add(iClass.getName());
      }

      // ejb/0fb7
      if (interceptorClasses.isEmpty()) {
        InterceptorOrder interceptorOrder = binding.getInterceptorOrder();

        // ejb/0fbf
        if (interceptorOrder != null)
          interceptorClasses = interceptorOrder.getInterceptorClasses();
      }

      for (String className : interceptorClasses) {
        Interceptor interceptor = getInterceptor(className);

        // ejb/0fb5 vs ejb/0fb6
        if (interceptor != null) {
          _interceptors.remove(interceptor);

          addInterceptor(interceptor);
        }
        else {
          interceptor = _ejbConfig.getInterceptor(className);

          interceptor.init();

          addInterceptor(interceptor);
        }
      }
    }

  }

  private Interceptor configureInterceptor(Class type)
    throws ConfigException
  {
    try {
      Interceptor interceptor = new Interceptor();

      interceptor.setInterceptorClass(type.getName());

      interceptor.init();

      return interceptor;
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Generates the class.
   */
  public void generate(JavaClassGenerator javaGen, boolean isAutoCompile)
    throws Exception
  {
    String fullClassName = _bean.getFullClassName();

    if (javaGen.preload(fullClassName) != null) {
    }
    else if (isAutoCompile) {
      javaGen.generate(_bean);

      /*
      GenClass genClass = assembleGenerator(fullClassName);

      if (genClass != null)
        javaGen.generate(genClass);
      */
    }
  }

  /**
   * Deploys the bean.
   */
  public AbstractServer deployServer(EjbContainer ejbContainer,
                                     JavaClassGenerator javaGen)
    throws ClassNotFoundException, ConfigException
  {
    throw new UnsupportedOperationException();
  }

  /**
   * Validates the remote interface.
   */
  protected void validateRemote(ApiClass objectClass)
    throws ConfigException
  {
    ApiClass beanClass = getEJBClassWrapper();
    String beanName = beanClass.getName();

    String objectName = objectClass.getName();

    if (! objectClass.isPublic())
      throw error(L.l("'{0}' must be public", objectName));

    if (! objectClass.isInterface())
      throw error(L.l("'{0}' must be an interface", objectName));

    for (ApiMethod method : objectClass.getMethods()) {
      String name = method.getName();
      Class []param = method.getParameterTypes();
      Class retType = method.getReturnType();

      Method javaMethod = method.getJavaMember();

      if (javaMethod.getDeclaringClass().isAssignableFrom(EJBObject.class))
        continue;
      if (javaMethod.getDeclaringClass().isAssignableFrom(EJBLocalObject.class))
        continue;

      if (EJBObject.class.isAssignableFrom(objectClass.getJavaClass()))
        validateException(method, java.rmi.RemoteException.class);

      if (name.startsWith("ejb")) {
        throw error(L.l("'{0}' forbidden in {1}.  Local or remote interfaces may not define ejbXXX methods.",
                        getFullMethodName(method),
                        objectName));
      }

      Class returnType = method.getReturnType();

      if (EJBObject.class.isAssignableFrom(objectClass.getJavaClass())
          && (EJBLocalObject.class.isAssignableFrom(returnType)
        || EJBLocalHome.class.isAssignableFrom(returnType))) {
        throw error(L.l("'{0}' must not return '{1}' in {2}.  Remote methods must not return local interfaces.",
                        getFullMethodName(method),
                        getShortClassName(returnType),
                        objectClass.getName()));
      }

      ApiMethod implMethod =
        validateRemoteImplMethod(method.getName(), param,
                                 method, objectClass);

      if (! returnType.equals(implMethod.getReturnType())) {
        throw error(L.l("{0}: '{1}' must return {2} to match {3}.{4}.  Business methods must return the same type as the interface.",
                        method.getDeclaringClass().getName(),
                        getFullMethodName(method),
                        implMethod.getReturnType().getName(),
                        implMethod.getDeclaringClass().getSimpleName(),
                        getFullMethodName(implMethod)));
      }

      validateExceptions(method, implMethod.getExceptionTypes());
    }
  }

  /**
   * Check that a method exists, is public, not abstract.
   *
   * @param methodName the name of the method to check for
   * @param args the expected method parameters
   *
   * @return the matching method
   */
  private ApiMethod validateRemoteImplMethod(String methodName,
                                           Class []param,
                                           ApiMethod sourceMethod,
                                           ApiClass sourceClass)
    throws ConfigException
  {
    ApiMethod method = null;
    ApiClass beanClass = getEJBClassWrapper();

    method = getMethod(beanClass, methodName, param);

    if (method == null && sourceMethod != null) {
      throw error(L.l("{0}: '{1}' expected to match {2}.{3}",
                      beanClass.getName(),
                      getFullMethodName(methodName, param),
                      sourceMethod.getDeclaringClass().getSimpleName(),
                      getFullMethodName(sourceMethod)));
    }
    else if (method == null) {
      throw error(L.l("{0}: '{1}' expected",
                      beanClass.getName(),
                      getFullMethodName(methodName, param)));
    }
    /*
      else if (Modifier.isAbstract(method.getModifiers()) &&
      getBeanManagedPersistence()) {
      throw error(L.l("{0}: '{1}' must not be abstract",
      beanClass.getName(),
      getFullMethodName(methodName, param)));
      }
    */
    else if (! method.isPublic()) {
      throw error(L.l("{0}: '{1}' must be public",
                      beanClass.getName(),
                      getFullMethodName(methodName, param)));
    }

    if (method.isStatic()) {
      throw error(L.l("{0}: '{1}' must not be static",
                      beanClass.getName(),
                      getFullMethodName(methodName, param)));
    }

    if (method.isFinal()) {
      throw error(L.l("{0}: '{1}' must not be final.",
                      beanClass.getName(),
                      getFullMethodName(methodName, param),
                      beanClass.getName()));
    }

    return method;
  }

  protected ApiMethod validateNonFinalMethod(String methodName, Class []param,
                                 boolean isOptional)
    throws ConfigException
  {
    if (isOptional && getMethod(_ejbClass, methodName, param) == null)
      return null;
    else
      return validateNonFinalMethod(methodName, param);
  }

  protected ApiMethod validateNonFinalMethod(String methodName, Class []param)
    throws ConfigException
  {
    return validateNonFinalMethod(methodName, param, null, null);
  }

  protected ApiMethod validateNonFinalMethod(String methodName, Class []param,
                                 ApiMethod sourceMethod, ApiClass sourceClass)
    throws ConfigException
  {
    return validateNonFinalMethod(methodName, param,
                                  sourceMethod, sourceClass, false);
  }

  /**
   * Check that a method exists, is public, not abstract, and not final.
   *
   * @param methodName the name of the method to check for
   * @param args the expected method parameters
   *
   * @return the matching method
   */
  protected ApiMethod validateNonFinalMethod(String methodName, Class []param,
           ApiMethod sourceMethod,
           ApiClass sourceClass,
           boolean isOptional)
    throws ConfigException
  {
    ApiMethod method = validateMethod(methodName, param,
              sourceMethod, sourceClass,
              isOptional);

    if (method == null && isOptional)
      return null;

    if (method.isFinal())
      throw error(L.l("{0}: '{1}' must not be final",
                      _ejbClass.getName(),
                      getFullMethodName(method)));


    if (method.isStatic())
      throw error(L.l("{0}: '{1}' must not be static",
                      _ejbClass.getName(),
                      getFullMethodName(method)));

    return method;
  }

  protected ApiMethod validateMethod(String methodName, Class []param)
    throws ConfigException
  {
    return validateMethod(methodName, param, null, null);
  }

  /**
   * Check that a method exists, is public and is not abstract.
   *
   * @param methodName the name of the method to check for
   * @param args the expected method parameters
   *
   * @return the matching method
   */
  protected ApiMethod validateMethod(String methodName, Class []param,
                         ApiMethod sourceMethod, ApiClass sourceClass)
    throws ConfigException
  {
    return validateMethod(methodName, param, sourceMethod, sourceClass, false);
  }

  /**
   * Check that a method exists, is public and is not abstract.
   *
   * @param methodName the name of the method to check for
   * @param args the expected method parameters
   *
   * @return the matching method
   */
  protected ApiMethod validateMethod(String methodName, Class []param,
         ApiMethod sourceMethod, ApiClass sourceClass,
         boolean isOptional)
    throws ConfigException
  {
    ApiMethod method = null;

    method = getMethod(_ejbClass, methodName, param);

    if (method == null && isOptional)
      return null;

    if (method == null && sourceMethod != null) {
      throw error(L.l("{0}: missing '{1}' needed to match {2}.{3}",
                      _ejbClass.getName(),
                      getFullMethodName(methodName, param),
                      sourceClass.getSimpleName(),
                      getFullMethodName(sourceMethod)));
    }
    else if (method == null) {
      throw error(L.l("{0}: expected '{1}'",
                      _ejbClass.getName(),
                      getFullMethodName(methodName, param)));
    }

    ApiClass declaringClass = method.getDeclaringClass();

    if (method.isAbstract()) {
      if (method.getDeclaringClass().getName().equals("javax.ejb.EntityBean"))
        throw error(L.l("{0}: '{1}' must not be abstract.  Entity beans must implement the methods in EntityBean.",
                        _ejbClass.getName(),
                        getFullMethodName(methodName, param)));
      else if (method.getDeclaringClass().getName().equals("javax.ejb.SessionBean"))
        throw error(L.l("{0}: '{1}' must not be abstract.  Session beans must implement the methods in SessionBean.",
                        _ejbClass.getName(),
                        getFullMethodName(methodName, param)));
      else if (sourceMethod != null)
        throw error(L.l("{0}: '{1}' must not be abstract.  All methods from '{2}' must be implemented in the bean.",
                        _ejbClass.getName(),
                        getFullMethodName(methodName, param),
                        sourceClass.getName()));
      else
        throw error(L.l("{0}: '{1}' must not be abstract.  Business methods must be implemented.",
                        _ejbClass.getName(),
                        getFullMethodName(methodName, param)));
    } else if (! method.isPublic()) {
      throw error(L.l("{0}: '{1}' must be public.  Business method implementations must be public.",
                      _ejbClass.getName(),
                      getFullMethodName(methodName, param)));
    }
    if (method.isStatic()) {
      throw error(L.l("{0}: '{1}' must not be static.  Business method implementations must not be static.",
                      _ejbClass.getName(),
                      getFullMethodName(method)));
    }

    return method;
  }

  public String getSkeletonName()
  {
    String className = getEJBClass().getName();
    int p = className.lastIndexOf('.');

    if (p > 0)
      className = className.substring(p + 1);

    String ejbName = getEJBName();

    String fullClassName = "_ejb." + ejbName + "." + className + "__" + getBeanType() + "Context";

    return JavaClassGenerator.cleanClassName(fullClassName);
  }

  /**
   * @return Type of bean (Stateful, Stateless, etc.)
   */
  protected String getBeanType() {
    return "Bean";
  }

  /**
   * Assembles the generator.
   */
  public GenClass assembleGenerator(String fullClassName)
    throws NoSuchMethodException, ConfigException
  {
    throw new UnsupportedOperationException();
  }

  /**
   * Introspects the bean's methods.
   */
  public void assembleBeanMethods()
    throws ConfigException
  {
    if (getEJBClassWrapper() == null)
      return;
   
    // find API methods matching an implementation method
    for (ApiMethod method : getEJBClassWrapper().getMethods()) {
      EjbBaseMethod ejbMethod = null;

      String name = method.getName();

      if (name.startsWith("ejb")) {
        ejbMethod = introspectEJBMethod(method);

        if (ejbMethod != null)
          _methodMap.put(ejbMethod.getMethod().getFullName(), ejbMethod);
      }
      else
        validateImplMethod(method);
    }
  }

  /**
   * Introspects an ejb method.
   */
  protected EjbBaseMethod introspectEJBMethod(ApiMethod method)
    throws ConfigException
  {
    return null;
  }

  /**
   * Validates an implementation method.
   */
  protected void validateImplMethod(ApiMethod method)
    throws ConfigException
  {
  }

  public CallChain getTransactionChain(CallChain next,
               ApiMethod apiMethod,
               ApiMethod implMethod,
               String prefix)
  {
    /*
    return TransactionChain.create(next,
           getTransactionAttribute(implMethod, prefix),
                                   apiMethod, implMethod, isEJB3(),
                                   _ejbConfig.getApplicationExceptions());
    */
    return null;
  }

  public CallChain getSecurityChain(CallChain next,
                                       ApiMethod method,
                                       String prefix)
  {
    EjbMethodPattern ejbMethod = getMethodPattern(method, prefix);

    ArrayList<String> roles = null;

    if (ejbMethod != null)
      roles = ejbMethod.getRoles();

    if (roles == null) {
      ejbMethod = getMethodPattern(null, prefix);
      if (ejbMethod != null)
        roles = ejbMethod.getRoles();
    }

    if (roles == null) {
      ejbMethod = getMethodPattern(method, null);
      if (ejbMethod != null)
        roles = ejbMethod.getRoles();
    }

    if (roles == null) {
      ejbMethod = getMethodPattern(null, null);
      if (ejbMethod != null)
        roles = ejbMethod.getRoles();
    }

    /*
    if (roles != null)
      return new UserInRoleChain(next, roles);
    else
      return next;
     */
    return next;
  }

  /**
   * Check that a method is public.
   *
   * @return the matching method
   */
  protected void validatePublicMethod(ApiMethod method)
    throws ConfigException
  {
    if (! method.isPublic()) {
      throw error(L.l("{0}: '{1}' must be public.",
                      _ejbClass.getName(),
                      getFullMethodName(method)));
    }
    else if (method.isStatic()) {
      throw error(L.l("{0}: '{1}' must not be static.",
                      _ejbClass.getName(),
                      getFullMethodName(method)));
    }
  }

  /**
   * True if we've already handled the method.
   */
  /*
  static boolean isOld(ApiMethod []methods, ApiMethod method, int index)
  {
    for (int i = 0; i < index; i++) {
      if (isEquiv(methods[i], method))
        return true;
    }

    return false;
  }
  */

  public static boolean isEquiv(ApiMethod oldMethod, ApiMethod method)
  {
    if (! oldMethod.getName().equals(method.getName()))
      return false;

    Class []oldParam = oldMethod.getParameterTypes();
    Class []param = method.getParameterTypes();

    if (oldParam.length != param.length)
      return false;

    for (int j = 0; j < param.length; j++) {
      if (! param[j].equals(oldParam[j]))
        return false;
    }

    return true;
  }

  /**
   * Returns the matching transaction attribute.
   */
  public TransactionAttributeType
    getTransactionAttribute(ApiMethod method, String intf)
  {
    if (! isContainerTransaction())
      return null;

    TransactionAttributeType transaction = null;

    EjbMethodPattern ejbMethod = getMethodPattern(null, null);

    if (ejbMethod != null)
      transaction = ejbMethod.getTransactionType();

    ejbMethod = getMethodPattern(method, null);

    if (ejbMethod != null)
      transaction = ejbMethod.getTransactionType();

    ejbMethod = getMethodPattern(method, intf);

    if (ejbMethod != null)
      transaction = ejbMethod.getTransactionType();

    return transaction;
  }

  /**
   * Finds the method in the class.
   *
   * @param cl owning class
   * @param method source method
   *
   * @return the matching method or null if non matches.
   */
  public ApiMethod getMethod(String methodName, Class []paramTypes)
  {
    return getMethod(getEJBClassWrapper(), methodName, paramTypes);
  }

  /**
   * Finds the method in the class.
   *
   * @param cl owning class
   * @param method source method
   *
   * @return the matching method or null if non matches.
   */
  public static ApiMethod getMethod(ApiClass cl, ApiMethod sourceMethod)
  {
    return getMethod(cl, sourceMethod.getName(),
                     sourceMethod.getParameterTypes());
  }

  /**
   * Finds the method in the class.
   *
   * @param apiList owning class
   * @param name method name to match
   * @param params method parameters to match
   *
   * @return the matching method or null if non matches.
   */
  public static ApiMethod getMethod(ArrayList<ApiClass> apiList,
            String name,
            Class []param)
  {
   
    for (int i = 0; i < apiList.size(); i++) {
      ApiMethod method = getMethod(apiList.get(i), name, param);

      if (method != null)
        return method;
    }

    return null;
  }

  /**
   * Finds the method in the class.
   *
   * @param cl owning class
   * @param name method name to match
   * @param params method parameters to match
   *
   * @return the matching method or null if non matches.
   */
  public static ApiMethod getMethod(ApiClass cl, String name, Class []param)
  {
    return cl.getMethod(name, param);
  }

  public boolean isCMP()
  {
    return false;
  }

  public boolean isCMP1()
  {
    return false;
  }

  public boolean isEJB3()
  {
    return ! (isCMP() || isCMP1());
  }

  public static boolean isMatch(ApiMethod methodA, ApiMethod methodB)
  {
    if (methodA == methodB)
      return true;
    else if (methodA == null || methodB == null)
      return false;
    else
      return isMatch(methodA, methodB.getName(), methodB.getParameterTypes());
  }

  public static boolean isMatch(ApiMethod method, String name, Class []param)
  {
    if (! method.getName().equals(name))
      return false;

    Class []mparam = method.getParameterTypes();

    if (mparam.length != param.length)
      return false;

    for (int j = 0; j < param.length; j++) {
      if (! mparam[j].equals(param[j]))
        return false;
    }

    return true;
  }

  /**
   * Finds the method in the class.
   *
   * @param cl owning class
   * @param name method name to match
   * @param params method parameters to match
   *
   * @return the matching method or null if non matches.
   */
  public static ApiMethod findMethod(MethodSignature sig, ApiClass cl, String intf)
  {
    if (cl == null)
      return null;

    for (ApiMethod method : cl.getMethods()) {
      if (sig.isMatch(method, intf))
        return method;
    }

    return null;
  }

  /**
   * Returns all the method in the class.
   */
  public static ArrayList<ApiMethod> getMethods(ArrayList<ApiClass> apiList)
  {
    ArrayList<ApiMethod> methodList = new ArrayList<ApiMethod>();

    for (ApiClass api : apiList) {
      for (ApiMethod method : api.getMethods()) {
        if (! methodList.contains(method))
          methodList.add(method);
      }
    }

    return methodList;
  }

  /**
   * Finds the method in the class.
   *
   * @param cl owning class
   * @param method source method
   *
   * @return the matching method or null if non matches.
   */
  public static ApiMethod findMethod(ArrayList<ApiMethod> methods, ApiMethod method)
  {
    loop:
    for (int i = 0; i < methods.size(); i++) {
      ApiMethod oldMethod = methods.get(i);

      if (oldMethod.equals(method))
  return oldMethod;
    }

    return null;
  }

  /**
   * Returns a printable version of a class.
   */
  public static String getClassName(Class cl)
  {
    if (cl == null)
      return "null";
    else if (cl.isArray())
      return getClassName(cl.getComponentType()) + "[]";
    else if (cl.getName().startsWith("java")) {
      int p = cl.getName().lastIndexOf('.');

      return cl.getName().substring(p + 1);
    }
    else
      return cl.getName();
  }

  /**
   * Returns a printable version of a class.
   */
  public static String getShortClassName(Class cl)
  {
    if (cl.isArray())
      return getShortClassName(cl.getComponentType()) + "[]";
    else
      return cl.getSimpleName();
  }

  /**
   * Tests is a method is declared in a class.
   */
  public boolean classHasMethod(ApiMethod method, ApiClass cl)
  {
    try {
      ApiMethod match = cl.getMethod(method.getName(),
             method.getParameterTypes());
      return match != null;
    } catch (Exception e) {
      return false;
    }
  }

  public void validateException(ApiMethod method, Class e)
    throws ConfigException
  {
    validateExceptions(method, new Class[] { e });
  }

  /**
   * Check that the method throws the expected exceptions.
   *
   * @param method the method to test
   * @param exn the expected exceptions
   */
  public void validateExceptions(ApiMethod method, Class []exn)
    throws ConfigException
  {
    Class []methodExceptions = method.getExceptionTypes();

    loop:
    for (int i = 0; i < exn.length; i++) {
      if (RuntimeException.class.isAssignableFrom(exn[i]))
        continue;

      for (int j = 0; j < methodExceptions.length; j++) {
        if (methodExceptions[j].isAssignableFrom(exn[i]))
          continue loop;
      }

      throw new ConfigException(L.l("{2}: '{0}' must throw {1}.",
                                    getFullMethodName(method),
                                    exn[i].getName(),
                                    method.getDeclaringClass().getName()));
    }
  }

  public void validateExceptions(ApiMethod caller, ApiMethod callee)
    throws ConfigException
  {
    Class []exn = callee.getExceptionTypes();
    Class missing = findMissingException(caller, exn);

    if (missing != null) {
      throw error(L.l("{0}: '{1}' must throw {2}.",
                      caller.getDeclaringClass().getName(),
                      getFullMethodName(caller),
                      getShortClassName(missing),
                      caller.getDeclaringClass().getName()) +
                  L.l(" {0} must throw all {1}.{2} exceptions.",
                      caller.getName(),
                      callee.getDeclaringClass().getSimpleName(),
                      callee.getName()));
    }
  }

  /**
   * Finds any exception in the exception array that the method isn't
   * throwing.
   *
   * @param method the method which should throw a superset of exceptions.
   * @param exn an array of exceptions the method should throw.
   *
   * @return the first missing exception
   */
  Class findMissingException(ApiMethod method, Class []exn)
    throws ConfigException
  {
    Class []methodExceptions = method.getExceptionTypes();

    for (int i = 0; i < exn.length; i++) {
      if (! hasException(method, exn[i])
    && ! RuntimeException.class.isAssignableFrom(exn[i]))
        return exn[i];
    }

    return null;
  }

  public boolean hasException(ApiMethod method, Class exn)
    throws ConfigException
  {
    Class []methodExceptions = method.getExceptionTypes();

    for (int j = 0; j < methodExceptions.length; j++) {
      if (methodExceptions[j].isAssignableFrom(exn))
        return true;
    }

    return false;
  }

  protected ApiMethod findFirstCreateMethod(ApiClass cl)
    throws ConfigException
  {
    for (ApiMethod method : cl.getMethods()) {
      if (method.getName().startsWith("create"))
  return method;
    }

    return null;
  }

  protected void introspectBean(ApiClass type, String defaultName)
    throws ConfigException
  {
    try {
      setEJBClassWrapper(type);

      String name = getEJBName();

      if (name == null || name.equals(""))
        name = defaultName;

      if (name == null || name.equals("")) {
        String className = type.getName();

        int p = className.lastIndexOf('.');

        if (p > 0)
          name = className.substring(p + 1);
        else
          name = className;
      }

      setEJBName(name);

      Local local = type.getAnnotation(Local.class);
      if (local != null) {
        Object []values = local.value();

        for (int i = 0; i < values.length; i++) {
          if (values[i] instanceof Class) {
            Class localClass = (Class) values[i];

            setLocalWrapper(new ApiClass(localClass));
          }
          else if (values[i] instanceof Class) {
            setLocal((Class) values[i]);
          }
        }
      }

      Remote remote = type.getAnnotation(Remote.class);
      if (remote != null) {
        Object []values = remote.value();

        for (int i = 0; i < values.length; i++) {
          if (values[i] instanceof Class) {
            Class remoteClass = (Class) values[i];

            setRemoteWrapper(new ApiClass(remoteClass));
          }
          else if (values[i] instanceof Class) {
            setRemote((Class) values[i]);
          }
        }

        // ejb/0f08: single interface
        if (values.length == 0) {
    // XXX: getGenericInterfaces
          Class []ifs = type.getJavaClass().getInterfaces();

          if (ifs.length == 1)
            setRemoteWrapper(new ApiClass(ifs[0]));
        }
      }

      TransactionAttribute xa = type.getAnnotation(TransactionAttribute.class);
      if (xa != null) {
        MethodSignature sig = new MethodSignature();
        sig.setMethodName("*");

        EjbMethodPattern pattern = createMethod(sig);

        setPatternTransaction(pattern, xa);
      }

      configureMethods(type);

      /*
        for (int i = 0; i < _initList.size(); i++)
        addInitProgram(_initList.get(i).getBuilderProgram());
      */
    } catch (ConfigException e) {
      throw e;
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      throw ConfigException.createLine(_location, e);
    }
  }

  private void configureMethods(ApiClass type)
    throws ConfigException
  {
    for (ApiMethod method : type.getMethods()) {
      TransactionAttribute xa
  = (TransactionAttribute) method.getAnnotation(TransactionAttribute.class);

      if (xa != null) {
        EjbMethodPattern pattern = createMethod(getSignature(method));

        setPatternTransaction(pattern, xa);
      }

      Annotation aroundInvoke = method.getAnnotation(AroundInvoke.class);

      // ejb/0fb8
      if (aroundInvoke != null) {
        _aroundInvokeMethodName = method.getName();
      }

      Annotation timeout = method.getAnnotation(Timeout.class);

      // ejb/0fj0
      if (timeout != null) {
        _timeoutMethodName = method.getName();
      }
    }
  }

  private void setPatternTransaction(EjbMethodPattern pattern,
                                     TransactionAttribute xa)
    throws ConfigException
  {
    TransactionAttributeType xaType = xa.value();

    pattern.setTransaction(xaType);
  }

  private MethodSignature getSignature(ApiMethod method)
    throws ConfigException
  {
    MethodSignature sig = new MethodSignature();

    sig.setMethodName(method.getName());

    Class []paramTypes = method.getParameterTypes();

    for (int i = 0; i < paramTypes.length; i++) {
      sig.addParam(paramTypes[i].getName());
    }

    return sig;
  }

  /**
   * Returns a full method name with arguments.
   */
  public static String getFullMethodName(ApiMethod method)
  {
    return getFullMethodName(method.getName(), method.getParameterTypes());
  }

  /**
   * Returns a full method name with arguments.
   */
  public static String getFullMethodName(String methodName, Class []params)
  {
    String name = methodName + "(";

    for (int i = 0; i < params.length; i++) {
      if (i != 0)
        name += ", ";

      name += params[i].getSimpleName();
    }

    return name + ")";
  }

  /**
   * Returns an error.
   */
  public ConfigException error(String msg)
  {
    if (_isInit && _filename != null)
      return new LineConfigException(_filename, _line, msg);
    else if (_isInit && ! "".equals(_location))
      return new LineConfigException(_location + msg);
    else
      return new ConfigException(msg);
  }

  /**
   * Returns an error.
   */
  public RuntimeException error(Exception e)
  {
    if (_filename != null)
      return LineConfigException.create(_filename, _line, e);
    else if (_location != null)
      return ConfigException.createLine(_location, e);
    else
      return ConfigException.create(e);
  }

  public String toString()
  {
    return getClass().getSimpleName() + "[" + _ejbName + "]";
  }
}
TOP

Related Classes of com.caucho.ejb.cfg.EjbBean

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.