/**
   * Construct a new instance.
   *
   * @param componentConfiguration the component configuration
   */
  public EJBComponentCreateService(
      final ComponentConfiguration componentConfiguration,
      final EjbJarConfiguration ejbJarConfiguration) {
    super(componentConfiguration);

    this.componentConfiguration = componentConfiguration;

    this.ejbJarConfiguration = ejbJarConfiguration;

    EJBComponentDescription ejbComponentDescription =
        (EJBComponentDescription) componentConfiguration.getComponentDescription();
    this.transactionManagementType = ejbComponentDescription.getTransactionManagementType();

    // CMTTx
    if (transactionManagementType.equals(TransactionManagementType.CONTAINER)) {
      // slurp some memory
      this.txAttrs =
          new ConcurrentHashMap<
              MethodIntf,
              ConcurrentMap<String, ConcurrentMap<ArrayKey, TransactionAttributeType>>>();
    } else {
      this.txAttrs = null;
    }
    List<ViewConfiguration> views = componentConfiguration.getViews();
    if (views != null) {
      for (ViewConfiguration view : views) {
        final MethodIntf viewType =
            ejbComponentDescription.getMethodIntf(view.getViewClass().getName());
        for (Method method : view.getProxyFactory().getCachedMethods()) {
          this.processTxAttr(ejbComponentDescription, viewType, method);
        }
      }
    }
    // FIXME: TODO: a temporary measure until EJBTHREE-2120 is fully resolved, let's create tx
    // attribute map
    // for the component methods. Once the issue is resolved, we should get rid of this block and
    // just rely on setting
    // up the tx attributes only for the views exposed by this component
    Set<Method> componentMethods = componentConfiguration.getDefinedComponentMethods();
    if (componentMethods != null) {
      for (Method method : componentMethods) {
        this.processTxAttr(ejbComponentDescription, MethodIntf.BEAN, method);
      }
    }
    final HashMap<String, ServiceName> viewServices = new HashMap<String, ServiceName>();
    for (ViewDescription view : componentConfiguration.getComponentDescription().getViews()) {
      viewServices.put(view.getViewClassName(), view.getServiceName());
    }
    this.viewServices = viewServices;
  }
  @Override
  public void configure(
      DeploymentPhaseContext context,
      ComponentConfiguration componentConfiguration,
      ViewDescription viewDescription,
      ViewConfiguration viewConfiguration)
      throws DeploymentUnitProcessingException {
    if (componentConfiguration.getComponentDescription() instanceof EJBComponentDescription
        == false) {
      throw MESSAGES.invalidEjbComponent(
          componentConfiguration.getComponentName(), componentConfiguration.getComponentClass());
    }
    final EJBComponentDescription ejbComponentDescription =
        (EJBComponentDescription) componentConfiguration.getComponentDescription();
    // if security is not enabled on the EJB, then do *not* add the security related interceptors
    if (!ejbComponentDescription.isSecurityEnabled()) {
      ROOT_LOGGER.debug(
          "Security is *not* enabled on EJB: "
              + ejbComponentDescription.getEJBName()
              + ", no security interceptors will apply");
      return;
    }
    final String viewClassName = viewDescription.getViewClassName();
    // setup the security context interceptor
    viewConfiguration.addViewInterceptor(
        new SecurityContextInterceptorFactory(), InterceptorOrder.View.SECURITY_CONTEXT);

    // now setup the rest of the method specific security interceptor(s)
    final List<Method> viewMethods = viewConfiguration.getProxyFactory().getCachedMethods();
    for (final Method viewMethod : viewMethods) {
      // TODO: proxy factory exposes non-public methods, is this a bug in the no-interface view?
      if (!Modifier.isPublic(viewMethod.getModifiers())) {
        continue;
      }
      if (viewMethod.getDeclaringClass() == WriteReplaceInterface.class) {
        continue;
      }
      final EJBMethodSecurityMetaData ejbMethodSecurityMetaData =
          new EJBMethodSecurityMetaData(componentConfiguration, viewClassName, viewMethod);
      // setup the authorization interceptor
      final Interceptor authorizationInterceptor =
          new AuthorizationInterceptor(ejbMethodSecurityMetaData, viewClassName, viewMethod);
      viewConfiguration.addViewInterceptor(
          viewMethod,
          new ImmediateInterceptorFactory(authorizationInterceptor),
          InterceptorOrder.View.EJB_SECURITY_AUTHORIZATION_INTERCEPTOR);
    }
  }
 @Override
 public void configure(
     final DeploymentPhaseContext context,
     final ComponentConfiguration componentConfiguration,
     final ViewDescription description,
     final ViewConfiguration configuration)
     throws DeploymentUnitProcessingException {
   final EJBComponentDescription ejbComponentDescription =
       (EJBComponentDescription) componentConfiguration.getComponentDescription();
   if (ejbComponentDescription.getTransactionManagementType()
       == TransactionManagementType.CONTAINER) {
     configuration.addViewInterceptor(
         EjbIIOPTransactionInterceptor.FACTORY, InterceptorOrder.View.EJB_IIOP_TRANSACTION);
   }
 }
 @Override
 public void configure(
     final DeploymentPhaseContext context,
     final ComponentConfiguration componentConfiguration,
     final ViewDescription viewDescription,
     final ViewConfiguration viewConfiguration)
     throws DeploymentUnitProcessingException {
   // setup a view interceptor which propagates remote transactions. This interceptor
   // should appear before the CMT/BMT interceptors so that the latter interceptors know about any
   // existing
   // tx for the invocation
   viewConfiguration.addViewInterceptor(
       EJBRemoteTransactionPropagatingInterceptorFactory.INSTANCE,
       InterceptorOrder.View.REMOTE_TRANSACTION_PROPAGATION_INTERCEPTOR);
 }
  /**
   * Construct a new instance.
   *
   * @param componentConfiguration the component configuration
   */
  public EJBComponentCreateService(
      final ComponentConfiguration componentConfiguration,
      final ApplicationExceptions applicationExceptions) {
    super(componentConfiguration);

    this.applicationExceptions = applicationExceptions;
    final EJBComponentDescription ejbComponentDescription =
        (EJBComponentDescription) componentConfiguration.getComponentDescription();
    this.transactionManagementType = ejbComponentDescription.getTransactionManagementType();

    this.timerService = ejbComponentDescription.getTimerService();
    this.policyContextID = ejbComponentDescription.getPolicyContextID();

    // CMTTx
    if (transactionManagementType.equals(TransactionManagementType.CONTAINER)) {
      this.txAttrs = new HashMap<MethodTransactionAttributeKey, TransactionAttributeType>();
      this.txTimeouts = new HashMap<MethodTransactionAttributeKey, Integer>();
    } else {
      this.txAttrs = null;
      this.txTimeouts = null;
    }
    // Setup the security metadata for the bean
    this.securityMetaData = new EJBSecurityMetaData(componentConfiguration);

    if (ejbComponentDescription.isTimerServiceRequired()) {
      Map<Method, InterceptorFactory> timeoutInterceptors =
          new IdentityHashMap<Method, InterceptorFactory>();
      for (Method method : componentConfiguration.getDefinedComponentMethods()) {
        if ((ejbComponentDescription.getTimeoutMethod() != null
                && ejbComponentDescription.getTimeoutMethod().equals(method))
            || ejbComponentDescription.getScheduleMethods().containsKey(method)) {
          final InterceptorFactory interceptorFactory =
              Interceptors.getChainedInterceptorFactory(
                  componentConfiguration.getAroundTimeoutInterceptors(method));
          timeoutInterceptors.put(method, interceptorFactory);
        }
      }
      this.timeoutInterceptors = timeoutInterceptors;
    } else {
      timeoutInterceptors = Collections.emptyMap();
    }

    List<ViewConfiguration> views = componentConfiguration.getViews();
    if (views != null) {
      for (ViewConfiguration view : views) {
        // TODO: Move this into a configurator
        final EJBViewConfiguration ejbView = (EJBViewConfiguration) view;
        final MethodIntf viewType = ejbView.getMethodIntf();
        for (Method method : view.getProxyFactory().getCachedMethods()) {
          // TODO: proxy factory exposes non-public methods, is this a bug in the no-interface view?
          if (!Modifier.isPublic(method.getModifiers())) continue;
          final Method componentMethod =
              getComponentMethod(
                  componentConfiguration, method.getName(), method.getParameterTypes());
          if (componentMethod != null) {
            this.processTxAttr(ejbComponentDescription, viewType, componentMethod);
          } else {
            this.processTxAttr(ejbComponentDescription, viewType, method);
          }
        }
      }
    }

    this.timeoutMethod = ejbComponentDescription.getTimeoutMethod();

    // FIXME: TODO: a temporary measure until EJBTHREE-2120 is fully resolved, let's create tx
    // attribute map
    // for the component methods. Once the issue is resolved, we should get rid of this block and
    // just rely on setting
    // up the tx attributes only for the views exposed by this component
    // AS7-899: We only want to process public methods of the proper sub-class.
    // (getDefinedComponentMethods returns all in random order)
    // TODO: use ClassReflectionIndex (low prio, because we store the result without class name)
    // (which is a bug: AS7-905)
    Set<Method> lifeCycle = new HashSet<>(componentConfiguration.getLifecycleMethods());
    for (Method method : componentConfiguration.getComponentClass().getMethods()) {
      this.processTxAttr(ejbComponentDescription, MethodIntf.BEAN, method);
      lifeCycle.remove(method);
    }
    // now handle non-public lifecycle methods declared on the bean class itself
    // see WFLY-4127
    for (Method method : lifeCycle) {
      if (method.getDeclaringClass().equals(componentConfiguration.getComponentClass())) {
        this.processTxAttr(ejbComponentDescription, MethodIntf.BEAN, method);
      }
    }

    final HashMap<String, ServiceName> viewServices = new HashMap<String, ServiceName>();
    for (ViewDescription view : componentConfiguration.getComponentDescription().getViews()) {
      viewServices.put(view.getViewClassName(), view.getServiceName());
    }
    this.viewServices = viewServices;
    final EjbHomeViewDescription localHome = ejbComponentDescription.getEjbLocalHomeView();
    this.ejbLocalHome =
        localHome == null ? null : ejbComponentDescription.getEjbLocalHomeView().getServiceName();
    final EjbHomeViewDescription home = ejbComponentDescription.getEjbHomeView();
    this.ejbHome = home == null ? null : home.getServiceName();
    final EJBViewDescription ejbObject = ejbComponentDescription.getEjbRemoteView();
    this.ejbObject = ejbObject == null ? null : ejbObject.getServiceName();
    final EJBViewDescription ejbLocalObject = ejbComponentDescription.getEjbLocalView();
    this.ejbLocalObject = ejbLocalObject == null ? null : ejbLocalObject.getServiceName();
    this.applicationName = componentConfiguration.getApplicationName();
    this.earApplicationName =
        componentConfiguration
            .getComponentDescription()
            .getModuleDescription()
            .getEarApplicationName();
    this.moduleName = componentConfiguration.getModuleName();
    this.distinctName =
        componentConfiguration.getComponentDescription().getModuleDescription().getDistinctName();
    this.shutDownInterceptorFactory = ejbComponentDescription.getShutDownInterceptorFactory();
  }
  @Override
  public void configure(
      final DeploymentPhaseContext context,
      final ComponentConfiguration componentConfiguration,
      final ViewDescription description,
      final ViewConfiguration configuration)
      throws DeploymentUnitProcessingException {
    // note that we don't have to handle all methods on the EJBObject, as some are handled client
    // side
    final DeploymentReflectionIndex index =
        context.getDeploymentUnit().getAttachment(Attachments.REFLECTION_INDEX);
    for (final Method method : configuration.getProxyFactory().getCachedMethods()) {

      if (method.getName().equals("getPrimaryKey") && method.getParameterTypes().length == 0) {
        configuration.addClientInterceptor(
            method,
            ViewDescription.CLIENT_DISPATCHER_INTERCEPTOR_FACTORY,
            InterceptorOrder.Client.CLIENT_DISPATCHER);
        configuration.addViewInterceptor(
            method, PRIMARY_KEY_INTERCEPTOR, InterceptorOrder.View.COMPONENT_DISPATCHER);
      } else if (method.getName().equals("remove") && method.getParameterTypes().length == 0) {
        handleRemoveMethod(componentConfiguration, configuration, index, method);

      } else if (method.getName().equals("getEJBLocalHome")
          && method.getParameterTypes().length == 0) {
        configuration.addClientInterceptor(
            method,
            ViewDescription.CLIENT_DISPATCHER_INTERCEPTOR_FACTORY,
            InterceptorOrder.Client.CLIENT_DISPATCHER);
        final GetHomeInterceptorFactory factory = new GetHomeInterceptorFactory();
        configuration.addViewInterceptor(
            method, factory, InterceptorOrder.View.COMPONENT_DISPATCHER);
        final SessionBeanComponentDescription componentDescription =
            (SessionBeanComponentDescription) componentConfiguration.getComponentDescription();
        componentConfiguration
            .getStartDependencies()
            .add(
                new DependencyConfigurator<ComponentStartService>() {
                  @Override
                  public void configureDependency(
                      final ServiceBuilder<?> serviceBuilder, final ComponentStartService service)
                      throws DeploymentUnitProcessingException {
                    EjbHomeViewDescription ejbLocalHomeView =
                        componentDescription.getEjbLocalHomeView();
                    if (ejbLocalHomeView == null) {
                      throw EjbLogger.ROOT_LOGGER.beanLocalHomeInterfaceIsNull(
                          componentDescription.getComponentName());
                    }
                    serviceBuilder.addDependency(
                        ejbLocalHomeView.getServiceName(),
                        ComponentView.class,
                        factory.getViewToCreate());
                  }
                });
      } else if (method.getName().equals("getEJBHome") && method.getParameterTypes().length == 0) {
        configuration.addClientInterceptor(
            method,
            ViewDescription.CLIENT_DISPATCHER_INTERCEPTOR_FACTORY,
            InterceptorOrder.Client.CLIENT_DISPATCHER);
        final GetHomeInterceptorFactory factory = new GetHomeInterceptorFactory();
        configuration.addViewInterceptor(
            method, factory, InterceptorOrder.View.COMPONENT_DISPATCHER);
        final SessionBeanComponentDescription componentDescription =
            (SessionBeanComponentDescription) componentConfiguration.getComponentDescription();
        componentConfiguration
            .getStartDependencies()
            .add(
                new DependencyConfigurator<ComponentStartService>() {
                  @Override
                  public void configureDependency(
                      final ServiceBuilder<?> serviceBuilder, final ComponentStartService service)
                      throws DeploymentUnitProcessingException {
                    EjbHomeViewDescription ejbHomeView = componentDescription.getEjbHomeView();
                    if (ejbHomeView == null) {
                      throw EjbLogger.ROOT_LOGGER.beanHomeInterfaceIsNull(
                          componentDescription.getComponentName());
                    }
                    serviceBuilder.addDependency(
                        ejbHomeView.getServiceName(),
                        ComponentView.class,
                        factory.getViewToCreate());
                  }
                });
      } else if (method.getName().equals("getHandle") && method.getParameterTypes().length == 0) {
        // ignore, handled client side
      } else if (method.getName().equals("isIdentical")
          && method.getParameterTypes().length == 1
          && (method.getParameterTypes()[0].equals(EJBObject.class)
              || method.getParameterTypes()[0].equals(EJBLocalObject.class))) {

        handleIsIdenticalMethod(componentConfiguration, configuration, index, method);
      } else {
        final Method componentMethod =
            ClassReflectionIndexUtil.findMethod(
                index,
                componentConfiguration.getComponentClass(),
                MethodIdentifier.getIdentifierForMethod(method));

        if (componentMethod != null) {
          if (!Modifier.isPublic(componentMethod.getModifiers())) {
            throw EjbLogger.ROOT_LOGGER.ejbBusinessMethodMustBePublic(componentMethod);
          }
          configuration.addViewInterceptor(
              method,
              new ImmediateInterceptorFactory(new ComponentDispatcherInterceptor(componentMethod)),
              InterceptorOrder.View.COMPONENT_DISPATCHER);
          configuration.addClientInterceptor(
              method,
              ViewDescription.CLIENT_DISPATCHER_INTERCEPTOR_FACTORY,
              InterceptorOrder.Client.CLIENT_DISPATCHER);
        } else if (method.getDeclaringClass() != Object.class
            && method.getDeclaringClass() != WriteReplaceInterface.class) {
          throw EjbLogger.ROOT_LOGGER.couldNotFindViewMethodOnEjb(
              method, description.getViewClassName(), componentConfiguration.getComponentName());
        }
      }
    }

    configuration.addClientPostConstructInterceptor(
        Interceptors.getTerminalInterceptorFactory(),
        InterceptorOrder.ClientPostConstruct.TERMINAL_INTERCEPTOR);
    configuration.addClientPreDestroyInterceptor(
        Interceptors.getTerminalInterceptorFactory(),
        InterceptorOrder.ClientPreDestroy.TERMINAL_INTERCEPTOR);
  }