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 */ 020package org.sonar.core.persistence; 021 022import org.apache.commons.io.IOUtils; 023import org.apache.commons.lang.StringUtils; 024import org.apache.ibatis.builder.xml.XMLMapperBuilder; 025import org.apache.ibatis.logging.LogFactory; 026import org.apache.ibatis.mapping.Environment; 027import org.apache.ibatis.session.Configuration; 028import org.apache.ibatis.session.ExecutorType; 029import org.apache.ibatis.session.SqlSession; 030import org.apache.ibatis.session.SqlSessionFactory; 031import org.apache.ibatis.session.SqlSessionFactoryBuilder; 032import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; 033import org.slf4j.LoggerFactory; 034import org.sonar.api.BatchComponent; 035import org.sonar.api.ServerComponent; 036import org.sonar.core.dashboard.ActiveDashboardDto; 037import org.sonar.core.dashboard.ActiveDashboardMapper; 038import org.sonar.core.dashboard.DashboardDto; 039import org.sonar.core.dashboard.DashboardMapper; 040import org.sonar.core.dashboard.WidgetDto; 041import org.sonar.core.dashboard.WidgetMapper; 042import org.sonar.core.dashboard.WidgetPropertyDto; 043import org.sonar.core.dashboard.WidgetPropertyMapper; 044import org.sonar.core.duplication.DuplicationMapper; 045import org.sonar.core.duplication.DuplicationUnitDto; 046import org.sonar.core.filter.CriterionDto; 047import org.sonar.core.filter.CriterionMapper; 048import org.sonar.core.filter.FilterColumnDto; 049import org.sonar.core.filter.FilterColumnMapper; 050import org.sonar.core.filter.FilterDto; 051import org.sonar.core.filter.FilterMapper; 052import org.sonar.core.properties.PropertiesMapper; 053import org.sonar.core.properties.PropertyDto; 054import org.sonar.core.purge.PurgeMapper; 055import org.sonar.core.purge.PurgeVendorMapper; 056import org.sonar.core.purge.PurgeableSnapshotDto; 057import org.sonar.core.resource.ResourceDto; 058import org.sonar.core.resource.ResourceIndexDto; 059import org.sonar.core.resource.ResourceIndexerMapper; 060import org.sonar.core.resource.ResourceMapper; 061import org.sonar.core.resource.SnapshotDto; 062import org.sonar.core.review.ReviewCommentDto; 063import org.sonar.core.review.ReviewCommentMapper; 064import org.sonar.core.review.ReviewDto; 065import org.sonar.core.review.ReviewMapper; 066import org.sonar.core.rule.RuleDto; 067import org.sonar.core.rule.RuleMapper; 068import org.sonar.core.template.LoadedTemplateDto; 069import org.sonar.core.template.LoadedTemplateMapper; 070import org.sonar.core.user.AuthorDto; 071import org.sonar.core.user.AuthorMapper; 072 073import java.io.InputStream; 074 075public class MyBatis implements BatchComponent, ServerComponent { 076 077 private final Database database; 078 private SqlSessionFactory sessionFactory; 079 080 public MyBatis(Database database) { 081 this.database = database; 082 } 083 084 public MyBatis start() { 085 LogFactory.useSlf4jLogging(); 086 Configuration conf = new Configuration(); 087 conf.setEnvironment(new Environment("production", createTransactionFactory(), database.getDataSource())); 088 conf.setUseGeneratedKeys(true); 089 conf.setLazyLoadingEnabled(false); 090 conf.getVariables().setProperty("_true", database.getDialect().getTrueSqlValue()); 091 conf.getVariables().setProperty("_false", database.getDialect().getFalseSqlValue()); 092 093 loadAlias(conf, "ActiveDashboard", ActiveDashboardDto.class); 094 loadAlias(conf, "Author", AuthorDto.class); 095 loadAlias(conf, "Filter", FilterDto.class); 096 loadAlias(conf, "Criterion", CriterionDto.class); 097 loadAlias(conf, "FilterColumn", FilterColumnDto.class); 098 loadAlias(conf, "Dashboard", DashboardDto.class); 099 loadAlias(conf, "DuplicationUnit", DuplicationUnitDto.class); 100 loadAlias(conf, "LoadedTemplate", LoadedTemplateDto.class); 101 loadAlias(conf, "Property", PropertyDto.class); 102 loadAlias(conf, "PurgeableSnapshot", PurgeableSnapshotDto.class); 103 loadAlias(conf, "Review", ReviewDto.class); 104 loadAlias(conf, "ReviewComment", ReviewCommentDto.class); 105 loadAlias(conf, "Resource", ResourceDto.class); 106 loadAlias(conf, "ResourceIndex", ResourceIndexDto.class); 107 loadAlias(conf, "Rule", RuleDto.class); 108 loadAlias(conf, "Snapshot", SnapshotDto.class); 109 loadAlias(conf, "SchemaMigration", SchemaMigrationDto.class); 110 loadAlias(conf, "Widget", WidgetDto.class); 111 loadAlias(conf, "WidgetProperty", WidgetPropertyDto.class); 112 113 loadMapper(conf, ActiveDashboardMapper.class); 114 loadMapper(conf, AuthorMapper.class); 115 loadMapper(conf, FilterMapper.class); 116 loadMapper(conf, CriterionMapper.class); 117 loadMapper(conf, FilterColumnMapper.class); 118 loadMapper(conf, DashboardMapper.class); 119 loadMapper(conf, DuplicationMapper.class); 120 loadMapper(conf, LoadedTemplateMapper.class); 121 loadMapper(conf, PropertiesMapper.class); 122 loadMapper(conf, PurgeMapper.class); 123 loadMapper(conf, PurgeVendorMapper.class); 124 loadMapper(conf, ResourceMapper.class); 125 loadMapper(conf, ReviewCommentMapper.class); 126 loadMapper(conf, ReviewMapper.class); 127 loadMapper(conf, ResourceIndexerMapper.class); 128 loadMapper(conf, RuleMapper.class); 129 loadMapper(conf, SchemaMigrationMapper.class); 130 loadMapper(conf, WidgetMapper.class); 131 loadMapper(conf, WidgetPropertyMapper.class); 132 133 sessionFactory = new SqlSessionFactoryBuilder().build(conf); 134 return this; 135 } 136 137 public SqlSessionFactory getSessionFactory() { 138 return sessionFactory; 139 } 140 141 public SqlSession openSession() { 142 return sessionFactory.openSession(ExecutorType.REUSE); 143 } 144 145 public BatchSession openBatchSession() { 146 SqlSession session = sessionFactory.openSession(ExecutorType.BATCH); 147 return new BatchSession(session); 148 } 149 150 public static void closeQuietly(SqlSession session) { 151 if (session != null) { 152 try { 153 session.close(); 154 } catch (Exception e) { 155 LoggerFactory.getLogger(MyBatis.class).warn("Fail to close session", e); 156 // do not re-throw the exception 157 } 158 } 159 } 160 161 private void loadMapper(Configuration conf, Class mapperClass) { 162 // trick to use database-specific XML files for a single Mapper Java interface 163 InputStream input = getPathToMapper(mapperClass); 164 try { 165 XMLMapperBuilder mapperParser = new XMLMapperBuilder(input, conf, mapperClass.getName(), conf.getSqlFragments()); 166 mapperParser.parse(); 167 conf.addLoadedResource(mapperClass.getName()); 168 169 } finally { 170 IOUtils.closeQuietly(input); 171 } 172 } 173 174 private InputStream getPathToMapper(Class mapperClass) { 175 InputStream input = getClass().getResourceAsStream( 176 "/" + StringUtils.replace(mapperClass.getName(), ".", "/") + "-" + database.getDialect().getId() + ".xml"); 177 if (input == null) { 178 input = getClass().getResourceAsStream("/" + StringUtils.replace(mapperClass.getName(), ".", "/") + ".xml"); 179 } 180 return input; 181 } 182 183 private void loadAlias(Configuration conf, String alias, Class dtoClass) { 184 conf.getTypeAliasRegistry().registerAlias(alias, dtoClass); 185 } 186 187 private static JdbcTransactionFactory createTransactionFactory() { 188 return new JdbcTransactionFactory(); 189 } 190 191}