/* * 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.search; import kr.debop4j.core.Local; import kr.debop4j.data.hibernate.interceptor.StatefulEntityInterceptor; import kr.debop4j.data.hibernate.interceptor.UpdateTimestampedInterceptor; 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.jdbc.JdbcTool; import kr.debop4j.search.dao.HibernateSearchDao; import kr.debop4j.search.dao.IHibernateSearchDao; import kr.debop4j.search.dao.SearchDao; import kr.debop4j.search.dao.SearchDaoImpl; import kr.debop4j.search.hibernate.model.SearchItem; import kr.debop4j.search.twitter.Twit; import lombok.extern.slf4j.Slf4j; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.kr.KoreanAnalyzer; import org.apache.lucene.util.Version; import org.hibernate.ConnectionReleaseMode; import org.hibernate.SessionFactory; import org.hibernate.cfg.Environment; import org.hibernate.cfg.beanvalidation.BeanValidationEventListener; import org.hibernate.event.spi.EventType; 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 org.springframework.orm.hibernate4.HibernateTransactionManager; import org.springframework.orm.hibernate4.LocalSessionFactoryBean; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.sql.DataSource; import java.io.IOException; import java.util.Properties; /** * hibernate와 hibernate-search를 이용한 검색 라이브러리를 테스트하기 위한 Spring 환경설정 파일입니다. * * @author 배성혁 ( sunghyouk.bae@gmail.com ) * @since 13. 2. 28. */ @Configuration @EnableTransactionManagement @ComponentScan(basePackageClasses = { UnitOfWorks.class, HibernateTool.class }) @Slf4j public class AppConfig { @Bean(destroyMethod = "close") public DataSource dataSource() { return JdbcTool.getEmbeddedHsqlDataSource(); } protected Properties hibernateProperties() { Properties props = new Properties(); props.put(Environment.DIALECT, "org.hibernate.dialect.HSQLDialect"); props.put(Environment.FORMAT_SQL, "true"); props.put(Environment.HBM2DDL_AUTO, "create"); // create | spawn | spawn-drop | update | validate props.put(Environment.SHOW_SQL, "true"); props.put(Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE); props.put(Environment.AUTOCOMMIT, "true"); props.put(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread"); props.put(Environment.STATEMENT_BATCH_SIZE, "50"); // hibernate-search 환경설정 props.put("hibernate.search.lucene_version", "LUCENE_36"); // 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"); // hibernate-search sharding // String defaultPrefix = "hibernate.search.default"; // props.put(defaultPrefix + ".sharding_strategy.nbr_of_shards", Integer.toString(Runtime.getRuntime().availableProcessors())); // props.put(defaultPrefix + ".directory_provider", FSDirectoryProvider.class.getName()); // hibernate-search performance settings // props.put("hibernate.search.worker.execution", "async"); props.put("hibernate.search.worker.thread_pool.size", "8"); props.put("hibernate.search.worker.buffer_queue.max", "1000"); 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", "1024"); // props.put("hibernate.search.default.exclusive_index_use", "true"); // Validator props.put("javax.persistencexml.validation.group.pre-persist", "javax.validation.groups.Default"); props.put("javax.persistencexml.validation.group.pre-update", "javax.validation.groups.Default"); return props; } private static String[] mappingPackages = new String[]{ SearchItem.class.getPackage().getName(), Twit.class.getPackage().getName() }; @Bean public SessionFactory sessionFactory() { if (log.isInfoEnabled()) log.info("SessionFactory Bean을 생성합니다..."); LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean(); factoryBean.setHibernateProperties(hibernateProperties()); factoryBean.setDataSource(dataSource()); factoryBean.setEntityInterceptor(hibernateInterceptor()); factoryBean.setPackagesToScan(mappingPackages); try { factoryBean.afterPropertiesSet(); if (log.isInfoEnabled()) log.info("SessionFactory Bean을 생성했습니다!!!"); SessionFactory sessionFactory = factoryBean.getObject(); // validator용 listener 추가 HibernateTool.registerEventListener(sessionFactory, beanValidationEventListener(), EventType.PRE_INSERT, EventType.PRE_UPDATE, EventType.PRE_DELETE); if (log.isInfoEnabled()) log.info("SessionFactory Bean을 생성했습니다!!!"); return sessionFactory; } catch (IOException e) { throw new RuntimeException("SessionFactory 빌드에 실패했습니다.", e); } } @Bean public BeanValidationEventListener beanValidationEventListener() { return new BeanValidationEventListener(); } @Bean public HibernateTransactionManager transactionManager() { return new HibernateTransactionManager(sessionFactory()); } @Bean public org.hibernate.Interceptor hibernateInterceptor() { return statuefulEntityInterceptor(); } @Bean public StatefulEntityInterceptor statuefulEntityInterceptor() { return new StatefulEntityInterceptor(); } @Bean public UpdateTimestampedInterceptor updateTimestampedInterceptor() { return new UpdateTimestampedInterceptor(); } @Bean public IUnitOfWorkFactory unitOfWorkFactory() { UnitOfWorkFactory factory = new UnitOfWorkFactory(); factory.setSessionFactory(sessionFactory()); return factory; } @Bean public IHibernateRepositoryFactory hibernateRepositoryFactory() { return new HibernateRepositoryFactory(); } private static final String LUCENE_ANALYZER_CURRENT = Analyzer.class.getName() + ".Current"; @Bean @Scope("prototype") public Analyzer luceneAnalyzer() { Analyzer analyzer = Local.get(LUCENE_ANALYZER_CURRENT, Analyzer.class); if (analyzer == null) { try { analyzer = new KoreanAnalyzer(Version.LUCENE_36); Local.put(LUCENE_ANALYZER_CURRENT, analyzer); } catch (Exception e) { throw new RuntimeException(e); } } return analyzer; } public static final String HIBERNATE_SEARCH_DAO_CURRENT = HibernateSearchDao.class.getName() + ".Current"; @Bean @Scope("prototype") public IHibernateSearchDao hibernateSearchDao() { IHibernateSearchDao dao = Local.get(HIBERNATE_SEARCH_DAO_CURRENT, HibernateSearchDao.class); if (dao == null) { dao = new HibernateSearchDao(); Local.put(HIBERNATE_SEARCH_DAO_CURRENT, dao); } return dao; } public static final String SEARCH_DAO_CURRENT = SearchDao.class.getName() + ".Current"; @Bean @Scope("prototype") public SearchDao searchDao() { SearchDao dao = Local.get(SEARCH_DAO_CURRENT, SearchDao.class); if (dao == null) { dao = new SearchDaoImpl(); //new SearchDaoImpl(sessionFactory()); Local.put(SEARCH_DAO_CURRENT, dao); } return dao; } }