private void processMethod(
      final DeploymentUnit deploymentUnit,
      final AnnotationInstance annotation,
      final MethodInfo methodInfo,
      final EEModuleClassDescription eeModuleClassDescription)
      throws DeploymentUnitProcessingException {

    final String methodName = methodInfo.name();
    if (!methodName.startsWith("set") || methodInfo.args().length != 1) {
      eeModuleClassDescription.setInvalid(
          MESSAGES.setterMethodOnlyAnnotation(annotation.name().toString(), methodInfo));
      return;
    }

    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 String injectionType = methodInfo.args()[0].name().toString();
    final InjectionSource bindingSource =
        this.getBindingSource(deploymentUnit, annotation, injectionType, eeModuleClassDescription);
    if (bindingSource != null) {
      final BindingConfiguration bindingConfiguration =
          new BindingConfiguration(localContextName, bindingSource);
      eeModuleClassDescription.getBindingConfigurations().add(bindingConfiguration);

      // setup the injection configuration
      final InjectionTarget injectionTarget =
          new MethodInjectionTarget(
              methodInfo.declaringClass().name().toString(),
              methodName,
              methodInfo.args()[0].name().toString());
      // source is always local ENC jndi name
      final InjectionSource injectionSource = new LookupInjectionSource(localContextName);
      final ResourceInjectionConfiguration injectionConfiguration =
          new ResourceInjectionConfiguration(injectionTarget, injectionSource);

      eeModuleClassDescription.addResourceInjection(injectionConfiguration);
    }
  }
  private void processField(
      final DeploymentUnit deploymentUnit,
      final AnnotationInstance annotation,
      final FieldInfo fieldInfo,
      final EEModuleClassDescription eeModuleClassDescription)
      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 = fieldInfo.declaringClass().name().toString() + "/" + fieldName;
    } else {
      localContextName = declaredName;
    }

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

    final String injectionType = injectionTypeDotName.toString();
    final InjectionSource bindingSource =
        this.getBindingSource(deploymentUnit, annotation, injectionType, eeModuleClassDescription);
    if (bindingSource != null) {
      final BindingConfiguration bindingConfiguration =
          new BindingConfiguration(localContextName, bindingSource);
      eeModuleClassDescription.getBindingConfigurations().add(bindingConfiguration);

      // setup the injection target
      final InjectionTarget injectionTarget =
          new FieldInjectionTarget(
              fieldInfo.declaringClass().name().toString(),
              fieldName,
              fieldInfo.type().name().toString());
      // source is always local ENC jndi
      final InjectionSource injectionSource = new LookupInjectionSource(localContextName);
      final ResourceInjectionConfiguration injectionConfiguration =
          new ResourceInjectionConfiguration(injectionTarget, injectionSource);
      eeModuleClassDescription.addResourceInjection(injectionConfiguration);
    }
  }
  private InjectionSource getBindingSource(
      final DeploymentUnit deploymentUnit,
      final AnnotationInstance annotation,
      String injectionTypeName,
      final EEModuleClassDescription classDescription)
      throws DeploymentUnitProcessingException {
    PersistenceUnitMetadata pu = getPersistenceUnit(deploymentUnit, annotation, classDescription);
    if (pu == null) {
      return null;
    }
    String scopedPuName = pu.getScopedPersistenceUnitName();
    ServiceName puServiceName = getPuServiceName(scopedPuName);
    if (isPersistenceContext(annotation)) {
      if (pu.getTransactionType() == PersistenceUnitTransactionType.RESOURCE_LOCAL) {
        classDescription.setInvalid(MESSAGES.cannotInjectResourceLocalEntityManager());
        return null;
      }
      AnnotationValue pcType = annotation.value("type");
      PersistenceContextType type =
          (pcType == null || PersistenceContextType.TRANSACTION.name().equals(pcType.asString()))
              ? PersistenceContextType.TRANSACTION
              : PersistenceContextType.EXTENDED;

      Map properties;
      AnnotationValue value = annotation.value("properties");
      AnnotationInstance[] props = value != null ? value.asNestedArray() : null;
      if (props != null) {
        properties = new HashMap();
        for (int source = 0; source < props.length; source++) {
          properties.put(props[source].value("name"), props[source].value("value"));
        }
      } else {
        properties = null;
      }

      return new PersistenceContextInjectionSource(
          type, properties, puServiceName, deploymentUnit, scopedPuName, injectionTypeName, pu);
    } else {
      return new PersistenceUnitInjectionSource(
          puServiceName, deploymentUnit, injectionTypeName, pu);
    }
  }
  private PersistenceUnitMetadata getPersistenceUnit(
      final DeploymentUnit deploymentUnit,
      final AnnotationInstance annotation,
      EEModuleClassDescription classDescription)
      throws DeploymentUnitProcessingException {

    final AnnotationValue puName = annotation.value("unitName");
    String searchName = null; // note:  a null searchName will match the first PU definition found

    if (puName != null) {
      searchName = puName.asString();
    }
    PersistenceUnitMetadata pu =
        PersistenceUnitSearch.resolvePersistenceUnitSupplier(deploymentUnit, searchName);
    if (null == pu) {
      classDescription.setInvalid(MESSAGES.persistenceUnitNotFound(searchName, deploymentUnit));
      return null;
    }
    return pu;
  }
  private void processClass(
      final DeploymentUnit deploymentUnit,
      final AnnotationInstance annotation,
      final EEModuleClassDescription eeModuleClassDescription)
      throws DeploymentUnitProcessingException {

    final AnnotationValue nameValue = annotation.value("name");
    if (nameValue == null || nameValue.asString().isEmpty()) {
      throw MESSAGES.classLevelAnnotationParameterRequired(annotation.name().toString(), "name");
    }
    final String name = nameValue.asString();
    String type = getClassLevelInjectionType(annotation);
    InjectionSource bindingSource =
        this.getBindingSource(deploymentUnit, annotation, type, eeModuleClassDescription);
    if (bindingSource != null) {
      final BindingConfiguration bindingConfiguration =
          new BindingConfiguration(name, bindingSource);
      eeModuleClassDescription.getBindingConfigurations().add(bindingConfiguration);
    }
  }
  private void process(
      final DeploymentUnit deploymentUnit,
      final String beanInterface,
      final String beanName,
      final String lookup,
      final ClassInfo classInfo,
      final InjectionTarget targetDescription,
      final String localContextName,
      final EEModuleDescription eeModuleDescription) {

    if (!isEmpty(lookup) && !isEmpty(beanName)) {
      logger.debug(
          "Both beanName = "
              + beanName
              + " and lookup = "
              + lookup
              + " have been specified in @EJB annotation."
              + " lookup will be given preference. Class: "
              + classInfo.name());
    }

    final EEModuleClassDescription classDescription =
        eeModuleDescription.addOrGetLocalClassDescription(classInfo.name().toString());

    final InjectionSource valueSource;
    EjbInjectionSource ejbInjectionSource = null;
    // give preference to lookup
    if (!isEmpty(lookup)) {
      if (!lookup.startsWith("java:")) {
        valueSource =
            new EjbLookupInjectionSource(lookup, targetDescription.getDeclaredValueClassName());
      } else {
        valueSource = createLookup(lookup, appclient);
      }
    } else if (!isEmpty(beanName)) {
      valueSource =
          ejbInjectionSource =
              new EjbInjectionSource(
                  beanName, beanInterface, localContextName, deploymentUnit, appclient);
    } else {
      valueSource =
          ejbInjectionSource =
              new EjbInjectionSource(beanInterface, localContextName, deploymentUnit, appclient);
    }
    if (ejbInjectionSource != null) {
      deploymentUnit.addToAttachmentList(
          EjbDeploymentAttachmentKeys.EJB_INJECTIONS, ejbInjectionSource);
    }
    // our injection comes from the local lookup, no matter what.
    final ResourceInjectionConfiguration injectionConfiguration =
        targetDescription != null
            ? new ResourceInjectionConfiguration(
                targetDescription, createLookup(localContextName, appclient))
            : null;

    // Create the binding from whence our injection comes.
    final BindingConfiguration bindingConfiguration =
        new BindingConfiguration(localContextName, valueSource);

    classDescription.getBindingConfigurations().add(bindingConfiguration);
    if (injectionConfiguration != null) {
      classDescription.addResourceInjection(injectionConfiguration);
    }
  }
  private void processComponentConfig(
      final DeploymentUnit deploymentUnit,
      final EEApplicationClasses applicationClasses,
      final Module module,
      final DeploymentReflectionIndex deploymentReflectionIndex,
      final SessionBeanComponentDescription description)
      throws DeploymentUnitProcessingException, ClassNotFoundException {
    String home = null;
    String localHome = null;

    // first check for annotations
    if (!MetadataCompleteMarker.isMetadataComplete(deploymentUnit)) {
      final EEModuleClassDescription clazz =
          applicationClasses.getClassByName(description.getComponentClassName());
      // we only care about annotations on the bean class itself
      if (clazz != null) {
        final ClassAnnotationInformation<LocalHome, String> localAnnotations =
            clazz.getAnnotationInformation(LocalHome.class);
        if (localAnnotations != null) {
          if (!localAnnotations.getClassLevelAnnotations().isEmpty()) {
            localHome = localAnnotations.getClassLevelAnnotations().get(0);

            if (description.getEjbLocalView() == null) {
              // If the local home is specified via annotation then the corresponding business
              // interface is implied
              // by the signature of the create method
              // See EJB 3.1 21.4.5
              final String localClassName =
                  this.inferLocalInterfaceFromLocalHome(
                      localHome, module, deploymentReflectionIndex, description);
              description.addEjbLocalObjectView(localClassName);
            }
          }
        }
        final ClassAnnotationInformation<RemoteHome, String> remoteAnnotations =
            clazz.getAnnotationInformation(RemoteHome.class);
        if (remoteAnnotations != null) {
          if (!remoteAnnotations.getClassLevelAnnotations().isEmpty()) {
            home = remoteAnnotations.getClassLevelAnnotations().get(0);
            if (description.getEjbRemoteView() == null) {
              // If the remote home is specified via annotation then the corresponding business
              // interface is implied
              // by the signature of the create method
              // See EJB 3.1 21.4.5
              final String remoteClassName =
                  this.inferRemoteInterfaceFromHome(
                      home, module, deploymentReflectionIndex, description);
              description.addEjbObjectView(remoteClassName);
            }
          }
        }
      }
    }
    // now allow the annotations to be overridden by the DD
    final SessionBeanMetaData descriptorData = description.getDescriptorData();
    if (descriptorData != null) {

      if (descriptorData.getHome() != null) {
        home = descriptorData.getHome();
      }
      if (descriptorData.getLocalHome() != null) {
        localHome = descriptorData.getLocalHome();
      }
    }
    if (localHome != null) {
      description.addLocalHome(localHome);
    }
    if (home != null) {
      description.addRemoteHome(home);
    }
    // finally see if we have to infer the remote or local interface from the home/local home views,
    // respectively
    if (description.getEjbHomeView() != null && description.getEjbRemoteView() == null) {
      final String remoteClassName =
          this.inferRemoteInterfaceFromHome(
              description.getEjbHomeView().getViewClassName(),
              module,
              deploymentReflectionIndex,
              description);
      description.addEjbObjectView(remoteClassName);
    }
    if (description.getEjbLocalHomeView() != null && description.getEjbLocalView() == null) {
      final String localClassName =
          this.inferLocalInterfaceFromLocalHome(
              description.getEjbLocalHomeView().getViewClassName(),
              module,
              deploymentReflectionIndex,
              description);
      description.addEjbLocalObjectView(localClassName);
    }
  }