001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * Sonar is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020 package org.sonar.core.persistence; 021 022 import org.apache.commons.io.IOUtils; 023 import org.apache.commons.lang.StringUtils; 024 import org.apache.ibatis.builder.xml.XMLMapperBuilder; 025 import org.apache.ibatis.logging.LogFactory; 026 import org.apache.ibatis.mapping.Environment; 027 import org.apache.ibatis.session.*; 028 import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; 029 import org.slf4j.LoggerFactory; 030 import org.sonar.api.BatchComponent; 031 import org.sonar.api.ServerComponent; 032 import org.sonar.core.dashboard.*; 033 import org.sonar.core.duplication.DuplicationMapper; 034 import org.sonar.core.duplication.DuplicationUnitDto; 035 import org.sonar.core.properties.PropertiesMapper; 036 import org.sonar.core.purge.PurgeMapper; 037 import org.sonar.core.purge.PurgeVendorMapper; 038 import org.sonar.core.purge.PurgeableSnapshotDto; 039 import org.sonar.core.resource.*; 040 import org.sonar.core.review.ReviewDto; 041 import org.sonar.core.review.ReviewMapper; 042 import org.sonar.core.rule.RuleDto; 043 import org.sonar.core.rule.RuleMapper; 044 import org.sonar.core.template.LoadedTemplateDto; 045 import org.sonar.core.template.LoadedTemplateMapper; 046 047 import java.io.IOException; 048 import java.io.InputStream; 049 050 public class MyBatis implements BatchComponent, ServerComponent { 051 052 private Database database; 053 private SqlSessionFactory sessionFactory; 054 055 public MyBatis(Database database) { 056 this.database = database; 057 } 058 059 public MyBatis start() throws IOException { 060 LogFactory.useSlf4jLogging(); 061 Configuration conf = new Configuration(); 062 conf.setEnvironment(new Environment("production", createTransactionFactory(), database.getDataSource())); 063 conf.setUseGeneratedKeys(true); 064 conf.setLazyLoadingEnabled(false); 065 conf.getVariables().setProperty("_true", database.getDialect().getTrueSqlValue()); 066 conf.getVariables().setProperty("_false", database.getDialect().getFalseSqlValue()); 067 068 loadAlias(conf, "ActiveDashboard", ActiveDashboardDto.class); 069 loadAlias(conf, "Dashboard", DashboardDto.class); 070 loadAlias(conf, "DuplicationUnit", DuplicationUnitDto.class); 071 loadAlias(conf, "LoadedTemplate", LoadedTemplateDto.class); 072 loadAlias(conf, "PurgeableSnapshot", PurgeableSnapshotDto.class); 073 loadAlias(conf, "Review", ReviewDto.class); 074 loadAlias(conf, "Resource", ResourceDto.class); 075 loadAlias(conf, "ResourceIndex", ResourceIndexDto.class); 076 loadAlias(conf, "Rule", RuleDto.class); 077 loadAlias(conf, "Snapshot", SnapshotDto.class); 078 loadAlias(conf, "Widget", WidgetDto.class); 079 loadAlias(conf, "WidgetProperty", WidgetPropertyDto.class); 080 081 loadMapper(conf, ActiveDashboardMapper.class); 082 loadMapper(conf, DashboardMapper.class); 083 loadMapper(conf, DuplicationMapper.class); 084 loadMapper(conf, LoadedTemplateMapper.class); 085 loadMapper(conf, PropertiesMapper.class); 086 loadMapper(conf, PurgeMapper.class); 087 loadMapper(conf, PurgeVendorMapper.class); 088 loadMapper(conf, ResourceMapper.class); 089 loadMapper(conf, ReviewMapper.class); 090 loadMapper(conf, ResourceIndexerMapper.class); 091 loadMapper(conf, RuleMapper.class); 092 loadMapper(conf, WidgetMapper.class); 093 loadMapper(conf, WidgetPropertyMapper.class); 094 095 sessionFactory = new SqlSessionFactoryBuilder().build(conf); 096 return this; 097 } 098 099 public SqlSessionFactory getSessionFactory() { 100 return sessionFactory; 101 } 102 103 public SqlSession openSession() { 104 return sessionFactory.openSession(ExecutorType.REUSE); 105 } 106 107 public BatchSession openBatchSession() { 108 SqlSession session = sessionFactory.openSession(ExecutorType.BATCH); 109 return new BatchSession(session); 110 } 111 112 public static void closeQuietly(SqlSession session) { 113 if (session != null) { 114 try { 115 session.close(); 116 } catch (Exception e) { 117 LoggerFactory.getLogger(MyBatis.class).warn("Fail to close session", e); 118 // do not re-throw the exception 119 } 120 } 121 } 122 123 private void loadMapper(Configuration conf, Class mapperClass) throws IOException { 124 // trick to use database-specific XML files for a single Mapper Java interface 125 InputStream input = getPathToMapper(mapperClass); 126 try { 127 XMLMapperBuilder mapperParser = new XMLMapperBuilder(input, conf, mapperClass.getName(), conf.getSqlFragments()); 128 mapperParser.parse(); 129 conf.addLoadedResource(mapperClass.getName()); 130 131 } finally { 132 IOUtils.closeQuietly(input); 133 } 134 } 135 136 private InputStream getPathToMapper(Class mapperClass) { 137 InputStream input = getClass().getResourceAsStream( 138 "/" + StringUtils.replace(mapperClass.getName(), ".", "/") + "-" + database.getDialect().getId() + ".xml"); 139 if (input == null) { 140 input = getClass().getResourceAsStream("/" + StringUtils.replace(mapperClass.getName(), ".", "/") + ".xml"); 141 } 142 return input; 143 } 144 145 private void loadAlias(Configuration conf, String alias, Class dtoClass) { 146 conf.getTypeAliasRegistry().registerAlias(alias, dtoClass); 147 } 148 149 private static JdbcTransactionFactory createTransactionFactory() { 150 return new JdbcTransactionFactory(); 151 } 152 153 }