/* * Copyright 2011-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package kr.debop4j.data.ogm.spring; import kr.debop4j.core.Local; import kr.debop4j.data.hibernate.interceptor.StatefulEntityInterceptor; import kr.debop4j.data.hibernate.repository.IHibernateRepositoryFactory; import kr.debop4j.data.hibernate.repository.impl.HibernateRepositoryFactory; import kr.debop4j.data.hibernate.tools.HibernateTool; import kr.debop4j.data.hibernate.unitofwork.IUnitOfWorkFactory; import kr.debop4j.data.hibernate.unitofwork.UnitOfWorkFactory; import kr.debop4j.data.hibernate.unitofwork.UnitOfWorks; import kr.debop4j.data.ogm.dao.HibernateOgmDao; import kr.debop4j.data.ogm.dao.IHibernateOgmDao; import lombok.extern.slf4j.Slf4j; import org.hibernate.SessionFactory; import org.hibernate.cfg.Environment; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.ogm.cfg.OgmConfiguration; import org.hibernate.ogm.datastore.impl.DatastoreServices; import org.hibernate.ogm.datastore.spi.DatastoreProvider; import org.hibernate.ogm.dialect.GridDialect; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.reflections.Reflections; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import javax.persistence.Entity; import java.util.Map; import java.util.Properties; import java.util.Set; /** * hibernate-ogm 의 환경설정을 Spring Configuration으로 구현합니다. * * @author 배성혁 ( sunghyouk.bae@gmail.com ) * @since 13. 3. 29 */ @Configuration @ComponentScan(basePackageClasses = { UnitOfWorks.class, HibernateTool.class }) @Slf4j public abstract class GridDatastoreConfigBase { /** DataStoreProvider 를 제공합니다. */ @Bean public DatastoreProvider datastoreProvider() { return (DatastoreProvider) getService(DatastoreProvider.class); } /** {@link GridDialect} 를 제공합니다. */ @Bean public GridDialect gridDialect() { return ((DatastoreServices) getService(DatastoreServices.class)).getGridDialect(); } /** hibernate-ogm용 configuration을 제공합니다. */ @Bean public OgmConfiguration ogmConfiguration() { log.info("hibernate-ogm용 configuration을 생성합니다..."); OgmConfiguration cfg = new OgmConfiguration(); for (String pkgName : getMappedPackageNames()) { log.info("Package를 추가합니다. package=[{}]", pkgName); final Reflections reflections = new Reflections(pkgName); final Set<Class<?>> classes = reflections.getTypesAnnotatedWith(Entity.class); for (final Class<?> clazz : classes) { log.info("Annotated Entity 를 등록합니다. Entity=[{}]", clazz); cfg.addAnnotatedClass(clazz); } // cfg.addPackage(pkgName); } for (Class annoatatedClass : getMappedEntities()) { cfg.addAnnotatedClass(annoatatedClass); log.info("AnnotatedEntity를 추가합니다. annotatedClass=[{}]", annoatatedClass.getName()); } log.info("hibernate용 interceptor릉록합니다., hibernateInterceptor=[{}]", hibernateInterceptor()); cfg.setInterceptor(hibernateInterceptor()); cfg.setProperties(getHibernateOgmProperties()); log.info("hibernate-ogm용 configuration을 생성했습니다!!!"); return cfg; } /** Hibernate SessionFactory 를 제공합니다. */ @Bean public SessionFactory sessionFactory() { log.info("hiberante-ogm 용 SessionFactory를 생성합니다..."); OgmConfiguration cfg = ogmConfiguration(); ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry(); SessionFactory sessionFactory = cfg.buildSessionFactory(serviceRegistry); log.info("hibernate-ogm용 SessionFactory를 생성했습니다!!!"); return sessionFactory; } @Bean public org.hibernate.Interceptor hibernateInterceptor() { return new StatefulEntityInterceptor(); } @Bean public IUnitOfWorkFactory unitOfWorkFactory() { log.info("UnitOfWorkFactory를 생성합니다..."); IUnitOfWorkFactory factory = new UnitOfWorkFactory(); factory.setSessionFactory(sessionFactory()); return factory; } @Bean public IHibernateRepositoryFactory hibernateRepositoryFactory() { return new HibernateRepositoryFactory(); } public static final String HIBERNATE_OGM_DAO_KEY = IHibernateOgmDao.class.getName() + ".Key"; @Bean @Scope("prototype") public IHibernateOgmDao hibernateOgmDao() { IHibernateOgmDao dao = Local.get(HIBERNATE_OGM_DAO_KEY, IHibernateOgmDao.class); if (dao == null) { dao = new HibernateOgmDao(); Local.put(HIBERNATE_OGM_DAO_KEY, dao); if (log.isDebugEnabled()) log.debug("IHibernateOgmDao 인스턴스를 생성했습니다."); } return dao; } /** * Database name * * @return database name */ abstract protected String getDatabaseName(); /** * 매핑할 엔티티가 속한 패키지의 이름 배열 * * @return 매핑할 엔티티가 속한 패키지의 이름 배열 */ protected String[] getMappedPackageNames() { return new String[0]; } /** * 매핑된 엔티티 배열 * * @return 메핑된 엔티티 배열 */ protected Class<?>[] getMappedEntities() { return new Class<?>[0]; } /** hibernate 용 속성을 설정합니다. */ protected Properties getHibernateProperties() { if (log.isDebugEnabled()) log.debug("Hibernate properties 를 설정합니다..."); Properties props = new Properties(); props.put(Environment.USE_NEW_ID_GENERATOR_MAPPINGS, true); props.put(Environment.HBM2DDL_AUTO, "none"); // Transaction 설정 !!! props.put(Environment.TRANSACTION_STRATEGY, "org.hibernate.transaction.JTATransactionFactory"); props.put(Environment.CURRENT_SESSION_CONTEXT_CLASS, "jta"); return props; } /** hibernate-ogm 용 속성을 반환합니다. */ protected Properties getHibernateOgmProperties() { if (log.isDebugEnabled()) log.debug("hibernate-ogm 용 property를 설정합니다..."); Properties props = getHibernateProperties(); // hibernate-search 설정 (hibernate-ogm에서는 hibernate criteria를 지원하지 않습니다. hibernate-search를 통해서 criteria를 지원합니다) // see Pro Hibernate and MongoDB pp. 246 // hibernate-search 환경설정 props.put("hibernate.search.default.indexmanager", "near-real-time"); props.put("hibernate.search.default.directory_provider", "filesystem"); props.put("hibernate.search.default.indexBase", ".lucene/indexes"); // simple|native|single|none props.put("hibernate.search.default.locking_strategy", "simple"); // hibernate-search index worker settings // props.put("hibernate.search.worker.execution", "async"); // sync // props.put("hibernate.search.worker.thread_pool.size", "8"); // default 1 // props.put("hibernate.search.worker.buffer_queue.max", "5000"); // default infinite // hibernate-search performance settings props.put("hibernate.search.default.indexwriter.max_buffered_doc", "true"); props.put("hibernate.search.default.indexwriter.max_merge_docs", "100"); props.put("hibernate.search.default.indexwriter.merge_factor", "20"); props.put("hibernate.search.default.indexwriter.term_index_interval", "default"); props.put("hibernate.search.default.indexwriter.ram_buffer_size", "2048"); props.put("hibernate.search.default.exclusive_index_use", "true"); for (Map.Entry entry : props.entrySet()) { log.debug("Property [{}]=[{}]", entry.getKey(), entry.getValue()); } return props; } /** * hibernate {@link ServiceRegistryImplementor}로부터 해당 서비스를 로드합니다. * * @param serviceImpl 서비스 구현체의 타입 * @return {@link ServiceRegistryImplementor}에 등록된 서비스 */ protected final org.hibernate.service.Service getService(Class<? extends org.hibernate.service.Service> serviceImpl) { if (log.isDebugEnabled()) log.debug("Service 를 로드합니다. serviceImpl=[{}]", serviceImpl.getName()); SessionFactoryImplementor sessionFactory = getSessionFactoryImplementor(); ServiceRegistryImplementor serviceRegistry = sessionFactory.getServiceRegistry(); return serviceRegistry.getService(serviceImpl); } /** * SessionFactoryImplementor를 제공합니다. * * @return {@link SessionFactoryImplementor} 인스턴스 */ protected final SessionFactoryImplementor getSessionFactoryImplementor() { return (SessionFactoryImplementor) sessionFactory(); } }