/**
   * Check the deployment annotation index for all classes with the @ManagedBean annotation. For
   * each class with the annotation, collect all the required information to create a managed bean
   * instance, and attach it to the context.
   *
   * @param phaseContext the deployment unit context
   * @throws DeploymentUnitProcessingException
   */
  public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
    final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
    final EEModuleDescription moduleDescription =
        deploymentUnit.getAttachment(org.jboss.as.ee.component.Attachments.EE_MODULE_DESCRIPTION);
    final String applicationName = moduleDescription.getAppName();
    final CompositeIndex compositeIndex =
        deploymentUnit.getAttachment(Attachments.COMPOSITE_ANNOTATION_INDEX);
    if (compositeIndex == null) {
      return;
    }
    final List<AnnotationInstance> instances =
        compositeIndex.getAnnotations(MANAGED_BEAN_ANNOTATION_NAME);
    if (instances == null || instances.isEmpty()) {
      return;
    }

    for (AnnotationInstance instance : instances) {
      AnnotationTarget target = instance.target();
      if (!(target instanceof ClassInfo)) {
        throw new DeploymentUnitProcessingException(
            "The ManagedBean annotation is only allowed at the class level: " + target);
      }
      final ClassInfo classInfo = (ClassInfo) target;
      final String beanClassName = classInfo.name().toString();

      // Get the managed bean name from the annotation
      final AnnotationValue nameValue = instance.value();
      final String beanName =
          nameValue == null || nameValue.asString().isEmpty()
              ? beanClassName
              : nameValue.asString();
      final ManagedBeanComponentDescription componentDescription =
          new ManagedBeanComponentDescription(
              beanName, beanClassName, moduleDescription.getModuleName(), applicationName);
      final ServiceName baseName =
          deploymentUnit.getServiceName().append("component").append(beanName);

      // Add the view
      componentDescription.getViewClassNames().add(beanClassName);

      // Bind the view to its two JNDI locations
      // TODO - this should be a bit more elegant
      final BindingDescription moduleBinding = new BindingDescription();
      moduleBinding.setAbsoluteBinding(true);
      moduleBinding.setBindingName("java:module/" + beanName);
      moduleBinding.setBindingType(beanClassName);
      moduleBinding.setReferenceSourceDescription(
          new ServiceBindingSourceDescription(baseName.append("VIEW").append(beanClassName)));
      componentDescription.getBindings().add(moduleBinding);
      final BindingDescription appBinding = new BindingDescription();
      appBinding.setAbsoluteBinding(true);
      appBinding.setBindingName("java:app/" + moduleDescription.getModuleName() + "/" + beanName);
      appBinding.setBindingType(beanClassName);
      appBinding.setReferenceSourceDescription(
          new ServiceBindingSourceDescription(baseName.append("VIEW").append(beanClassName)));
      componentDescription.getBindings().add(appBinding);
      moduleDescription.addComponent(componentDescription);
    }
  }
  private BindingDescription processClassResource(
      final DeploymentUnit deploymentUnit,
      final AnnotationInstance annotation,
      final ClassInfo classInfo,
      final AbstractComponentDescription componentDescription,
      final DeploymentPhaseContext phaseContext)
      throws DeploymentUnitProcessingException {

    final AnnotationValue nameValue = annotation.value("name");
    if (nameValue == null || nameValue.asString().isEmpty()) {
      throw new IllegalArgumentException("Class level annotations must provide a name.");
    }
    final String name = nameValue.asString();
    final String type = classInfo.name().toString();
    final BindingDescription bindingDescription = new BindingDescription();
    bindingDescription.setDependency(true);
    bindingDescription.setBindingName(name);
    bindingDescription.setBindingType(type);
    ServiceName injectorName =
        getInjectorServiceName(
            deploymentUnit, annotation, componentDescription, phaseContext, name, type);
    bindingDescription.setReferenceSourceDescription(
        new ServiceBindingSourceDescription(injectorName));
    return bindingDescription;
  }
  private BindingDescription processMethod(
      final DeploymentUnit deploymentUnit,
      final AnnotationInstance annotation,
      final MethodInfo methodInfo,
      final AbstractComponentDescription componentDescription,
      final DeploymentPhaseContext phaseContext)
      throws DeploymentUnitProcessingException {

    final String methodName = methodInfo.name();
    if (!methodName.startsWith("set") || methodInfo.args().length != 1) {
      throw new IllegalArgumentException(
          "injection target is invalid.  Only setter methods are allowed: " + methodInfo);
    }

    final String contextNameSuffix =
        methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
    final AnnotationValue declaredNameValue = annotation.value("name");
    final String declaredName = declaredNameValue != null ? declaredNameValue.asString() : null;
    final String localContextName;
    if (declaredName == null || declaredName.isEmpty()) {
      localContextName = methodInfo.declaringClass().name().toString() + "/" + contextNameSuffix;
    } else {
      localContextName = declaredName;
    }

    final DotName declaredType = methodInfo.returnType().name();
    final DotName injectionType =
        declaredType == null || declaredType.toString().equals(Object.class.getName())
            ? methodInfo.returnType().name()
            : declaredType;
    final BindingDescription bindingDescription = new BindingDescription();
    bindingDescription.setDependency(true);
    bindingDescription.setBindingName(localContextName);
    final String injectionTypeName = injectionType.toString();
    bindingDescription.setBindingType(injectionTypeName);

    ServiceName injectorName =
        getInjectorServiceName(
            deploymentUnit,
            annotation,
            componentDescription,
            phaseContext,
            methodName,
            injectionTypeName);

    bindingDescription.setReferenceSourceDescription(
        new ServiceBindingSourceDescription(injectorName));

    // setup the injection target
    final InjectionTargetDescription targetDescription = new InjectionTargetDescription();
    targetDescription.setName(methodName);
    targetDescription.setClassName(methodInfo.declaringClass().name().toString());
    targetDescription.setType(InjectionTargetDescription.Type.METHOD);
    targetDescription.setValueClassName(injectionTypeName);
    bindingDescription.getInjectionTargetDescriptions().add(targetDescription);
    return bindingDescription;
  }
  private BindingDescription processField(
      final DeploymentUnit deploymentUnit,
      final AnnotationInstance annotation,
      final FieldInfo fieldInfo,
      final AbstractComponentDescription componentDescription,
      final DeploymentPhaseContext phaseContext)
      throws DeploymentUnitProcessingException {

    final String fieldName = fieldInfo.name();
    final AnnotationValue declaredNameValue = annotation.value("name");
    final String declaredName = declaredNameValue != null ? declaredNameValue.asString() : null;
    final String localContextName;
    if (declaredName == null || declaredName.isEmpty()) {
      localContextName = "java:comp/env/persistence" + "/" + fieldName;
    } else {
      localContextName = declaredName;
    }

    // final AnnotationValue declaredTypeValue = annotation.value("type");
    final DotName declaredType = fieldInfo.type().name();
    final DotName injectionType =
        declaredType == null || declaredType.toString().equals(Object.class.getName())
            ? fieldInfo.type().name()
            : declaredType;

    BindingDescription bindingDescription = new BindingDescription();
    bindingDescription.setDependency(true);
    bindingDescription.setBindingName(localContextName);
    final String injectionTypeName = injectionType.toString();
    bindingDescription.setBindingType(injectionTypeName);

    ServiceName injectorName =
        getInjectorServiceName(
            deploymentUnit,
            annotation,
            componentDescription,
            phaseContext,
            fieldName,
            injectionTypeName);
    bindingDescription.setReferenceSourceDescription(
        new ServiceBindingSourceDescription(injectorName));

    // setup the injection target
    final InjectionTargetDescription targetDescription = new InjectionTargetDescription();
    targetDescription.setName(fieldName);
    targetDescription.setClassName(fieldInfo.declaringClass().name().toString());
    targetDescription.setType(InjectionTargetDescription.Type.FIELD);
    targetDescription.setValueClassName(injectionTypeName);
    bindingDescription.getInjectionTargetDescriptions().add(targetDescription);

    return bindingDescription;
  }