/**
   * Process the deployment unit and deploy appropriate MC beans (see details below) if it
   * corresponds to a no-interface view deployment.
   *
   * <p>If any beans in the unit are eligible for no-interface view, then internally this method
   * creates a {@link NoInterfaceViewJNDIBinderFacade} MC bean for the no-interface view.
   *
   * <p>The {@link NoInterfaceViewJNDIBinderFacade}, thus created, will be dependent on the {@link
   * ControllerState#DESCRIBED} state of the container (endpoint) MC bean. This way, we ensure that
   * this {@link NoInterfaceViewJNDIBinderFacade} will be deployed only after the corresponding
   * container MC bean moves to {@link ControllerState#DESCRIBED} state.
   */
  public void deploy(DeploymentUnit unit) throws DeploymentException {

    if (logger.isTraceEnabled()) {
      logger.trace("Deploying unit " + unit.getName());
    }
    // get processed metadata
    JBossMetaData metaData = unit.getAttachment(INPUT, JBossMetaData.class);
    if (metaData == null) {
      if (logger.isTraceEnabled()) logger.trace("No JBossMetadata for unit : " + unit.getName());
      return;
    }
    // work on the ejbs
    JBossEnterpriseBeansMetaData beans = metaData.getEnterpriseBeans();
    for (JBossEnterpriseBeanMetaData bean : beans) {
      if (bean.isSession()) {
        if (logger.isTraceEnabled()) {
          logger.trace(
              "Found bean of type session: " + bean.getEjbClass() + " in unit " + unit.getName());
        }
        // too bad
        if (bean instanceof JBossSessionBean31MetaData) {
          // Process for no-interface view
          deploy(unit, (JBossSessionBean31MetaData) bean);
        }
      }
    }
  }
  /**
   * A template pattern implementation of the deploy() method. This method calls the {@link
   * #performDeploy(WebApplication, String, WebDescriptorParser) performDeploy()} method to perform
   * the container specific deployment steps and registers the returned WebApplication in the
   * deployment map. The steps performed are:
   *
   * <p>ClassLoader appClassLoader = thread.getContextClassLoader(); URLClassLoader warLoader =
   * URLClassLoader.newInstance(empty, appClassLoader); thread.setContextClassLoader(warLoader);
   * WebDescriptorParser webAppParser = ...; WebMetaData metaData = di.metaData; // Create JACC
   * permissions, contextID, etc. ... WebApplication warInfo = new WebApplication(metaData);
   * performDeploy(warInfo, warUrl, webAppParser); deploymentMap.put(warUrl, warInfo);
   * thread.setContextClassLoader(appClassLoader);
   *
   * <p>The subclass performDeploy() implementation needs to invoke processEnc(loader, warInfo) to
   * have the JNDI java:comp/env namespace setup before any web app component can access this
   * namespace.
   *
   * <p>Also, an MBean for each servlet deployed should be created and its JMX ObjectName placed
   * into the DeploymentInfo.mbeans list so that the JSR77 layer can create the approriate model
   * view. The servlet MBean needs to provide access to the min, max and total time in milliseconds.
   * Expose this information via MinServiceTime, MaxServiceTime and TotalServiceTime attributes to
   * integrate seemlessly with the JSR77 factory layer.
   *
   * @param unit The deployment info that contains the context-root element value from the J2EE
   *     application/module/web application.xml descriptor. This may be null if war was is not being
   *     deployed as part of an enterprise application. It also contains the URL of the web
   *     application war.
   */
  public synchronized WebApplication start(DeploymentUnit unit, JBossWebMetaData metaData)
      throws Exception {
    Thread thread = Thread.currentThread();
    ClassLoader appClassLoader = thread.getContextClassLoader();
    WebApplication webApp = null;
    try {
      // Create a classloader for the war to ensure a unique ENC
      ClassLoader warLoader = unit.getClassLoader();
      thread.setContextClassLoader(warLoader);
      String webContext = metaData.getContextRoot();

      // Get the war URL
      URL warUrl = unit.getAttachment("org.jboss.web.expandedWarURL", URL.class);
      if (warUrl == null && unit instanceof VFSDeploymentUnit) {
        VFSDeploymentUnit vdu = VFSDeploymentUnit.class.cast(unit);
        warUrl = VFSUtils.getRealURL(vdu.getRoot());
      }

      // Dynamic WebMetaData deployments might not provide an URL
      // We use the DEploymentUnit name as identifier instead.
      // The JAXWS Endpoint API for example does this.
      String warURLString = (warUrl != null ? warUrl.toExternalForm() : unit.getName());

      // Strip any jar: url syntax. This should be be handled by the vfs
      if (warURLString.startsWith("jar:"))
        warURLString = warURLString.substring(4, warURLString.length() - 2);

      log.debug("webContext: " + webContext);
      log.debug("warURL: " + warURLString);

      // Register the permissions with the JACC layer
      String contextID = metaData.getJaccContextID();
      if (contextID == null) contextID = unit.getSimpleName();
      metaData.setJaccContextID(contextID);

      webApp = new WebApplication(metaData);
      webApp.setClassLoader(warLoader);
      webApp.setDeploymentUnit(unit);
      performDeploy(webApp, warURLString);
    } finally {
      thread.setContextClassLoader(appClassLoader);
    }
    return webApp;
  }
  /**
   * Creates a {@link NoInterfaceViewJNDIBinderFacade} MC bean for the no-interface view represented
   * by the <code>sessionBeanMetaData</code>. The {@link NoInterfaceViewJNDIBinderFacade} is created
   * only if the bean is eligible for a no-interface view as defined by the EJB3.1 spec
   *
   * <p>The {@link NoInterfaceViewJNDIBinderFacade}, thus created, will be dependent on the {@link
   * ControllerState#DESCRIBED} state of the container (endpoint) MC bean. This way, we ensure that
   * this {@link NoInterfaceViewJNDIBinderFacade} will be deployed only after the corresponding
   * container MC bean moves to {@link ControllerState#DESCRIBED} state.
   *
   * @param unit Deployment unit
   * @param sessionBeanMetaData Session bean metadata
   * @throws DeploymentException If any exceptions are encountered during processing of the
   *     deployment unit
   */
  private void deploy(DeploymentUnit unit, JBossSessionBean31MetaData sessionBeanMetaData)
      throws DeploymentException {
    try {
      if (!sessionBeanMetaData.isNoInterfaceBean()) {
        if (logger.isTraceEnabled()) {
          logger.trace(
              "Bean class "
                  + sessionBeanMetaData.getEjbClass()
                  + " is not eligible for no-interface view");
        }
        return;
      }
      Class<?> beanClass =
          Class.forName(sessionBeanMetaData.getEjbClass(), false, unit.getClassLoader());

      String containerMCBeanName = sessionBeanMetaData.getContainerName();
      if (logger.isTraceEnabled()) {
        logger.trace(
            "Container name for bean "
                + sessionBeanMetaData.getEjbName()
                + " in unit "
                + unit
                + " is "
                + containerMCBeanName);
      }
      if (containerMCBeanName == null) {
        // The container name is set in the metadata only after the creation of the container
        // However, this deployer does not have an dependency on the creation of a container,
        // so getting the container name from the bean metadata won't work. Need to do a
        // different/better way
        // String containerMCBeanName = sessionBeanMetaData.getContainerName();
        containerMCBeanName = getContainerName(unit, sessionBeanMetaData);
      }

      // Create the NoInterfaceViewJNDIBinder (MC bean) and add a dependency on the DESCRIBED
      // state of the container (endpoint) MC bean
      NoInterfaceViewJNDIBinderFacade noInterfaceViewJNDIBinderFacade =
          new NoInterfaceViewJNDIBinderFacade(new InitialContext(), beanClass, sessionBeanMetaData);
      String noInterfaceViewMCBeanName = unit.getName() + "$" + sessionBeanMetaData.getEjbName();
      BeanMetaDataBuilder builder =
          BeanMetaDataBuilder.createBuilder(
              noInterfaceViewMCBeanName, noInterfaceViewJNDIBinderFacade.getClass().getName());
      builder.setConstructorValue(noInterfaceViewJNDIBinderFacade);

      // add dependency
      AbstractInjectionValueMetaData injectMetaData =
          new AbstractInjectionValueMetaData(containerMCBeanName);
      // EJBTHREE-2166 - Depending on DESCRIBED state and then pushing to INSTALLED
      // through MC API, won't work. So for now, just depend on INSTALLED state.
      // injectMetaData.setDependentState(ControllerState.DESCRIBED);
      injectMetaData.setDependentState(ControllerState.INSTALLED);
      injectMetaData.setFromContext(FromContext.CONTEXT);

      // Too bad we have to know the field name. Need to do more research on MC to see if we can
      // add property metadata based on type instead of field name.
      builder.addPropertyMetaData("endpointContext", injectMetaData);

      // Add this as an attachment
      unit.addAttachment(
          BeanMetaData.class + ":" + noInterfaceViewMCBeanName, builder.getBeanMetaData());

      logger.debug(
          "No-interface JNDI binder for container "
              + containerMCBeanName
              + " has been created and added to the deployment unit "
              + unit);

    } catch (Throwable t) {
      DeploymentException.rethrowAsDeploymentException(
          "Could not create no-interface view for "
              + sessionBeanMetaData.getEjbClass()
              + " in unit "
              + unit.getName(),
          t);
    }
  }