/** Overrides the default behaviour to including binding of Grails domain classes. */
  @Override
  protected void secondPassCompile() throws MappingException {
    if (configLocked) {
      return;
    }

    // set the class loader to load Groovy classes
    if (grailsApplication != null) {
      Thread.currentThread().setContextClassLoader(grailsApplication.getClassLoader());
    }

    configureDomainBinder(grailsApplication, domainClasses);

    for (GrailsDomainClass domainClass : domainClasses) {
      if (!GrailsHibernateUtil.usesDatasource(domainClass, dataSourceName)) {
        continue;
      }
      final Mappings mappings = super.createMappings();
      Mapping m = binder.getMapping(domainClass);
      mappings.setAutoImport(m == null || m.getAutoImport());
      binder.bindClass(domainClass, mappings, sessionFactoryBeanName);
    }

    super.secondPassCompile();
    configLocked = true;
  }
  /**
   * Sets custom naming strategy specified in configuration or the default {@link
   * ImprovedNamingStrategy}.
   */
  private void configureNamingStrategy() {
    NamingStrategy strategy = null;
    Object customStrategy = grailsApplication.getFlatConfig().get("hibernate.naming_strategy");
    if (customStrategy != null) {
      Class<?> namingStrategyClass = null;
      if (customStrategy instanceof Class<?>) {
        namingStrategyClass = (Class<?>) customStrategy;
      } else {
        try {
          namingStrategyClass =
              grailsApplication.getClassLoader().loadClass(customStrategy.toString());
        } catch (ClassNotFoundException e) {
          // ignore
        }
      }

      if (namingStrategyClass != null) {
        try {
          strategy = (NamingStrategy) namingStrategyClass.newInstance();
        } catch (InstantiationException e) {
          // ignore
        } catch (IllegalAccessException e) {
          // ignore
        }
      }
    }

    if (strategy == null) {
      strategy = ImprovedNamingStrategy.INSTANCE;
    }

    setNamingStrategy(strategy);
  }
  public void afterPropertiesSet() throws Exception {
    if (grailsApplication == null) {
      return;
    }

    String dsName =
        Mapping.DEFAULT_DATA_SOURCE.equals(dataSourceName)
            ? "dataSource"
            : "dataSource_" + dataSourceName;
    getProperties().put(Environment.DATASOURCE, applicationContext.getBean(dsName));
    getProperties()
        .put(Environment.CURRENT_SESSION_CONTEXT_CLASS, GrailsSessionContext.class.getName());
    getProperties().put(AvailableSettings.CLASSLOADERS, grailsApplication.getClassLoader());
    resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(applicationContext);

    configureNamingStrategy();
    GrailsClass[] existingDomainClasses =
        grailsApplication.getArtefacts(DomainClassArtefactHandler.TYPE);
    for (GrailsClass existingDomainClass : existingDomainClasses) {
      addDomainClass((GrailsDomainClass) existingDomainClass);
    }

    ArtefactHandler handler = grailsApplication.getArtefactHandler(DomainClassArtefactHandler.TYPE);
    if (!(handler instanceof AnnotationDomainClassArtefactHandler)) {
      return;
    }

    Set<String> jpaDomainNames =
        ((AnnotationDomainClassArtefactHandler) handler).getJpaClassNames();
    if (jpaDomainNames == null) {
      return;
    }

    final ClassLoader loader = grailsApplication.getClassLoader();
    for (String jpaDomainName : jpaDomainNames) {
      try {
        addAnnotatedClass(loader.loadClass(jpaDomainName));
      } catch (ClassNotFoundException e) {
        // impossible condition
      }
    }
  }
  /** Overrides the default behaviour to including binding of Grails domain classes. */
  @Override
  protected void secondPassCompile() throws MappingException {
    final Thread currentThread = Thread.currentThread();
    final ClassLoader originalContextLoader = currentThread.getContextClassLoader();
    if (!configLocked) {
      if (LOG.isDebugEnabled())
        LOG.debug(
            "[GrailsAnnotationConfiguration] ["
                + domainClasses.size()
                + "] Grails domain classes to bind to persistence runtime");

      // do Grails class configuration
      configureDomainBinder(binder, grailsApplication, domainClasses);

      for (GrailsDomainClass domainClass : domainClasses) {

        final String fullClassName = domainClass.getFullName();

        String hibernateConfig = fullClassName.replace('.', '/') + ".hbm.xml";
        final ClassLoader loader = originalContextLoader;
        // don't configure Hibernate mapped classes
        if (loader.getResource(hibernateConfig) != null) continue;

        final Mappings mappings = super.createMappings();
        if (!GrailsHibernateUtil.usesDatasource(domainClass, dataSourceName)) {
          continue;
        }

        LOG.debug(
            "[GrailsAnnotationConfiguration] Binding persistent class [" + fullClassName + "]");

        Mapping m = binder.getMapping(domainClass);
        mappings.setAutoImport(m == null || m.getAutoImport());
        binder.bindClass(domainClass, mappings, sessionFactoryBeanName);
      }
    }

    try {
      currentThread.setContextClassLoader(grailsApplication.getClassLoader());
      super.secondPassCompile();
      createSubclassForeignKeys();
    } finally {
      currentThread.setContextClassLoader(originalContextLoader);
    }

    configLocked = true;
  }
  @Override
  public SessionFactory buildSessionFactory() throws HibernateException {

    // set the class loader to load Groovy classes
    if (grailsApplication != null) {
      LOG.debug(
          "[GrailsAnnotationConfiguration] Setting context class loader to Grails GroovyClassLoader");
      Thread.currentThread().setContextClassLoader(grailsApplication.getClassLoader());
    }

    // work around for HHH-2624
    Map<String, Type> empty = new HashMap<String, Type>();
    addFilterDefinition(new FilterDefinition("dynamicFilterEnabler", "1=1", empty));

    SessionFactory sessionFactory = null;

    ClassLoader appClassLoader =
        (ClassLoader) getProperties().get(AvailableSettings.APP_CLASSLOADER);
    Thread currentThread = Thread.currentThread();
    ClassLoader threadContextClassLoader = currentThread.getContextClassLoader();
    boolean overrideClassLoader =
        (appClassLoader != null && !appClassLoader.equals(threadContextClassLoader));
    if (overrideClassLoader) {
      currentThread.setContextClassLoader(appClassLoader);
    }

    try {
      ConfigurationHelper.resolvePlaceHolders(getProperties());

      EventListenerIntegrator eventListenerIntegrator =
          new EventListenerIntegrator(hibernateEventListeners, eventListeners);
      BootstrapServiceRegistry bootstrapServiceRegistry =
          new BootstrapServiceRegistryBuilder().with(eventListenerIntegrator).build();

      setSessionFactoryObserver(
          new SessionFactoryObserver() {
            private static final long serialVersionUID = 1;

            public void sessionFactoryCreated(SessionFactory factory) {}

            public void sessionFactoryClosed(SessionFactory factory) {
              ((ServiceRegistryImplementor) serviceRegistry).destroy();
            }
          });

      StandardServiceRegistryBuilder standardServiceRegistryBuilder =
          new StandardServiceRegistryBuilder(bootstrapServiceRegistry)
              .applySettings(getProperties());
      sessionFactory = super.buildSessionFactory(standardServiceRegistryBuilder.build());
      serviceRegistry = ((SessionFactoryImplementor) sessionFactory).getServiceRegistry();
    } finally {
      if (overrideClassLoader) {
        currentThread.setContextClassLoader(threadContextClassLoader);
      }
    }

    if (grailsApplication != null) {
      GrailsHibernateUtil.configureHibernateDomainClasses(
          sessionFactory, sessionFactoryBeanName, grailsApplication);
    }

    return sessionFactory;
  }