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}