/**
   * Used to register the method validation interceptor binding annotation.
   *
   * @param beforeBeanDiscoveryEvent event fired before the bean discovery process starts
   * @param beanManager the bean manager.
   */
  public void beforeBeanDiscovery(
      @Observes BeforeBeanDiscovery beforeBeanDiscoveryEvent, final BeanManager beanManager) {
    Contracts.assertNotNull(
        beforeBeanDiscoveryEvent, "The BeforeBeanDiscovery event cannot be null");
    Contracts.assertNotNull(beanManager, "The BeanManager cannot be null");

    // Register the interceptor explicitly. This way, no beans.xml is needed
    AnnotatedType<ValidationInterceptor> annotatedType =
        beanManager.createAnnotatedType(ValidationInterceptor.class);
    beforeBeanDiscoveryEvent.addAnnotatedType(annotatedType);
  }
  /**
   * Registers beans for {@code ValidatorFactory} and {@code Validator} if not yet present.
   *
   * @param afterBeanDiscoveryEvent event fired after the bean discovery phase.
   * @param beanManager the bean manager.
   */
  public void afterBeanDiscovery(
      @Observes AfterBeanDiscovery afterBeanDiscoveryEvent, BeanManager beanManager) {
    Contracts.assertNotNull(afterBeanDiscoveryEvent, "The AfterBeanDiscovery event cannot be null");
    Contracts.assertNotNull(beanManager, "The BeanManager cannot be null");

    ValidationProviderHelper defaultProviderHelper =
        ValidationProviderHelper.forDefaultProvider(validatorFactory);
    ValidationProviderHelper hvProviderHelper = ValidationProviderHelper.forHibernateValidator();

    // register default VF if none has been provided by the application or another PE
    if (defaultValidatorFactoryBean == null) {
      defaultValidatorFactoryBean = new ValidatorFactoryBean(beanManager, defaultProviderHelper);
      if (hibernateValidatorFactoryBean == null && defaultProviderHelper.isHibernateValidator()) {
        hibernateValidatorFactoryBean = defaultValidatorFactoryBean;
      }
      afterBeanDiscoveryEvent.addBean(defaultValidatorFactoryBean);
    }

    // register VF with @HibernateValidator qualifier in case it hasn't been contributed by the
    // application and the
    // default VF registered by ourselves isn't for Hibernate Validator
    if (hibernateValidatorFactoryBean == null) {
      hibernateValidatorFactoryBean = new ValidatorFactoryBean(beanManager, hvProviderHelper);
      afterBeanDiscoveryEvent.addBean(hibernateValidatorFactoryBean);
    }

    // register default validator if required
    if (defaultValidatorBean == null) {
      defaultValidatorBean =
          new ValidatorBean(beanManager, defaultValidatorFactoryBean, defaultProviderHelper);
      if (hibernateValidatorBean == null && defaultProviderHelper.isHibernateValidator()) {
        hibernateValidatorBean = defaultValidatorBean;
      }
      afterBeanDiscoveryEvent.addBean(defaultValidatorBean);
    }

    // register validator with @HibernateValidator if required
    if (hibernateValidatorBean == null) {
      hibernateValidatorBean =
          new ValidatorBean(beanManager, hibernateValidatorFactoryBean, hvProviderHelper);
      afterBeanDiscoveryEvent.addBean(hibernateValidatorBean);
    }
  }
  /**
   * Used to register the method validation interceptor bindings.
   *
   * @param processAnnotatedTypeEvent event fired for each annotated type
   * @param <T> the annotated type
   */
  public <T> void processAnnotatedType(
      @Observes @WithAnnotations({Constraint.class, Valid.class, ValidateOnExecution.class})
          ProcessAnnotatedType<T> processAnnotatedTypeEvent) {
    Contracts.assertNotNull(
        processAnnotatedTypeEvent, "The ProcessAnnotatedType event cannot be null");

    // validation globally disabled
    if (!isExecutableValidationEnabled) {
      return;
    }

    AnnotatedType<T> type = processAnnotatedTypeEvent.getAnnotatedType();
    Set<AnnotatedCallable<? super T>> constrainedCallables = determineConstrainedCallables(type);

    if (!constrainedCallables.isEmpty()) {
      ValidationEnabledAnnotatedType<T> wrappedType =
          new ValidationEnabledAnnotatedType<T>(type, constrainedCallables);
      processAnnotatedTypeEvent.setAnnotatedType(wrappedType);
    }
  }
  /**
   * Watches the {@code ProcessBean} event in order to determine whether beans for {@code
   * ValidatorFactory} and {@code Validator} already have been registered by some other component.
   *
   * @param processBeanEvent event fired for each enabled bean.
   */
  public void processBean(@Observes ProcessBean<?> processBeanEvent) {
    Contracts.assertNotNull(processBeanEvent, "The ProcessBean event cannot be null");

    Bean<?> bean = processBeanEvent.getBean();

    if (bean.getTypes().contains(ValidatorFactory.class) || bean instanceof ValidatorFactoryBean) {
      if (bean.getQualifiers().contains(defaultQualifier)) {
        defaultValidatorFactoryBean = bean;
      }
      if (bean.getQualifiers().contains(hibernateValidatorQualifier)) {
        hibernateValidatorFactoryBean = bean;
      }
    } else if (bean.getTypes().contains(Validator.class) || bean instanceof ValidatorBean) {
      if (bean.getQualifiers().contains(defaultQualifier)) {
        defaultValidatorBean = bean;
      }
      if (bean.getQualifiers().contains(hibernateValidatorQualifier)) {
        hibernateValidatorBean = bean;
      }
    }
  }