/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.db;
import com.google.common.annotations.VisibleForTesting;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.sonar.api.Startable;
import org.sonar.db.ce.CeActivityMapper;
import org.sonar.db.ce.CeQueueMapper;
import org.sonar.db.ce.CeScannerContextMapper;
import org.sonar.db.ce.CeTaskInputMapper;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentDtoWithSnapshotId;
import org.sonar.db.component.ComponentKeyUpdaterMapper;
import org.sonar.db.component.ComponentLinkDto;
import org.sonar.db.component.ComponentLinkMapper;
import org.sonar.db.component.ComponentMapper;
import org.sonar.db.component.FilePathWithHashDto;
import org.sonar.db.component.ResourceDto;
import org.sonar.db.component.ResourceMapper;
import org.sonar.db.component.SnapshotDto;
import org.sonar.db.component.SnapshotMapper;
import org.sonar.db.component.UuidWithProjectUuidDto;
import org.sonar.db.component.ViewsSnapshotDto;
import org.sonar.db.debt.RequirementMigrationDto;
import org.sonar.db.duplication.DuplicationMapper;
import org.sonar.db.duplication.DuplicationUnitDto;
import org.sonar.db.event.EventDto;
import org.sonar.db.event.EventMapper;
import org.sonar.db.issue.IssueChangeDto;
import org.sonar.db.issue.IssueChangeMapper;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.issue.IssueMapper;
import org.sonar.db.loadedtemplate.LoadedTemplateDto;
import org.sonar.db.loadedtemplate.LoadedTemplateMapper;
import org.sonar.db.measure.MeasureDto;
import org.sonar.db.measure.MeasureMapper;
import org.sonar.db.measure.custom.CustomMeasureDto;
import org.sonar.db.measure.custom.CustomMeasureMapper;
import org.sonar.db.metric.MetricMapper;
import org.sonar.db.notification.NotificationQueueDto;
import org.sonar.db.notification.NotificationQueueMapper;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationMapper;
import org.sonar.db.organization.OrganizationMemberDto;
import org.sonar.db.organization.OrganizationMemberMapper;
import org.sonar.db.permission.AuthorizationMapper;
import org.sonar.db.permission.GroupPermissionDto;
import org.sonar.db.permission.GroupPermissionMapper;
import org.sonar.db.permission.UserPermissionDto;
import org.sonar.db.permission.UserPermissionMapper;
import org.sonar.db.permission.template.PermissionTemplateCharacteristicDto;
import org.sonar.db.permission.template.PermissionTemplateCharacteristicMapper;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonar.db.permission.template.PermissionTemplateGroupDto;
import org.sonar.db.permission.template.PermissionTemplateMapper;
import org.sonar.db.permission.template.PermissionTemplateUserDto;
import org.sonar.db.property.InternalPropertiesMapper;
import org.sonar.db.property.InternalPropertyDto;
import org.sonar.db.property.PropertiesMapper;
import org.sonar.db.property.ScrapPropertyDto;
import org.sonar.db.purge.IdUuidPair;
import org.sonar.db.purge.PurgeMapper;
import org.sonar.db.purge.PurgeableAnalysisDto;
import org.sonar.db.qualitygate.ProjectQgateAssociationDto;
import org.sonar.db.qualitygate.ProjectQgateAssociationMapper;
import org.sonar.db.qualitygate.QualityGateConditionDto;
import org.sonar.db.qualitygate.QualityGateConditionMapper;
import org.sonar.db.qualitygate.QualityGateDto;
import org.sonar.db.qualitygate.QualityGateMapper;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleMapper;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.QProfileChangeMapper;
import org.sonar.db.qualityprofile.QualityProfileDto;
import org.sonar.db.qualityprofile.QualityProfileMapper;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleMapper;
import org.sonar.db.rule.RuleParamDto;
import org.sonar.db.rule.RuleRepositoryMapper;
import org.sonar.db.schemamigration.SchemaMigrationDto;
import org.sonar.db.schemamigration.SchemaMigrationMapper;
import org.sonar.db.source.FileSourceMapper;
import org.sonar.db.user.AuthorDto;
import org.sonar.db.user.AuthorMapper;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.GroupMapper;
import org.sonar.db.user.GroupMembershipDto;
import org.sonar.db.user.GroupMembershipMapper;
import org.sonar.db.user.RoleMapper;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserGroupDto;
import org.sonar.db.user.UserGroupMapper;
import org.sonar.db.user.UserMapper;
import org.sonar.db.user.UserTokenCount;
import org.sonar.db.user.UserTokenDto;
import org.sonar.db.user.UserTokenMapper;
import org.sonar.db.webhook.WebhookDeliveryMapper;
public class MyBatis implements Startable {
private final Database database;
private SqlSessionFactory sessionFactory;
public MyBatis(Database database) {
this.database = database;
}
@Override
public void start() {
LogFactory.useSlf4jLogging();
MyBatisConfBuilder confBuilder = new MyBatisConfBuilder(database);
// DTO aliases, keep them sorted alphabetically
confBuilder.loadAlias("ActiveRule", ActiveRuleDto.class);
confBuilder.loadAlias("ActiveRuleParam", ActiveRuleParamDto.class);
confBuilder.loadAlias("Author", AuthorDto.class);
confBuilder.loadAlias("Component", ComponentDto.class);
confBuilder.loadAlias("ComponentLink", ComponentLinkDto.class);
confBuilder.loadAlias("ComponentWithSnapshot", ComponentDtoWithSnapshotId.class);
confBuilder.loadAlias("CustomMeasure", CustomMeasureDto.class);
confBuilder.loadAlias("DuplicationUnit", DuplicationUnitDto.class);
confBuilder.loadAlias("Event", EventDto.class);
confBuilder.loadAlias("FilePathWithHash", FilePathWithHashDto.class);
confBuilder.loadAlias("Group", GroupDto.class);
confBuilder.loadAlias("GroupMembership", GroupMembershipDto.class);
confBuilder.loadAlias("GroupPermission", GroupPermissionDto.class);
confBuilder.loadAlias("IdUuidPair", IdUuidPair.class);
confBuilder.loadAlias("InternalProperty", InternalPropertyDto.class);
confBuilder.loadAlias("IssueChange", IssueChangeDto.class);
confBuilder.loadAlias("KeyLongValue", KeyLongValue.class);
confBuilder.loadAlias("Issue", IssueDto.class);
confBuilder.loadAlias("LoadedTemplate", LoadedTemplateDto.class);
confBuilder.loadAlias("Measure", MeasureDto.class);
confBuilder.loadAlias("NotificationQueue", NotificationQueueDto.class);
confBuilder.loadAlias("Organization", OrganizationDto.class);
confBuilder.loadAlias("OrganizationMember", OrganizationMemberDto.class);
confBuilder.loadAlias("PermissionTemplateCharacteristic", PermissionTemplateCharacteristicDto.class);
confBuilder.loadAlias("PermissionTemplateGroup", PermissionTemplateGroupDto.class);
confBuilder.loadAlias("PermissionTemplate", PermissionTemplateDto.class);
confBuilder.loadAlias("PermissionTemplateUser", PermissionTemplateUserDto.class);
confBuilder.loadAlias("ProjectQgateAssociation", ProjectQgateAssociationDto.class);
confBuilder.loadAlias("PurgeableAnalysis", PurgeableAnalysisDto.class);
confBuilder.loadAlias("QualityGateCondition", QualityGateConditionDto.class);
confBuilder.loadAlias("QualityGate", QualityGateDto.class);
confBuilder.loadAlias("QualityProfile", QualityProfileDto.class);
confBuilder.loadAlias("RequirementMigration", RequirementMigrationDto.class);
confBuilder.loadAlias("Resource", ResourceDto.class);
confBuilder.loadAlias("RuleParam", RuleParamDto.class);
confBuilder.loadAlias("Rule", RuleDto.class);
confBuilder.loadAlias("SchemaMigration", SchemaMigrationDto.class);
confBuilder.loadAlias("ScrapProperty", ScrapPropertyDto.class);
confBuilder.loadAlias("Snapshot", SnapshotDto.class);
confBuilder.loadAlias("UserGroup", UserGroupDto.class);
confBuilder.loadAlias("UserPermission", UserPermissionDto.class);
confBuilder.loadAlias("UserTokenCount", UserTokenCount.class);
confBuilder.loadAlias("UserToken", UserTokenDto.class);
confBuilder.loadAlias("User", UserDto.class);
confBuilder.loadAlias("UuidWithProjectUuid", UuidWithProjectUuidDto.class);
confBuilder.loadAlias("ViewsSnapshot", ViewsSnapshotDto.class);
// ResourceMapper has to be loaded before IssueMapper because this last one used it
confBuilder.loadMapper(ResourceMapper.class);
// keep them sorted alphabetically
Class<?>[] mappers = {
ActiveRuleMapper.class,
AuthorMapper.class,
AuthorizationMapper.class,
CeActivityMapper.class,
CeQueueMapper.class,
CeScannerContextMapper.class,
CeTaskInputMapper.class,
ComponentKeyUpdaterMapper.class,
ComponentLinkMapper.class,
ComponentMapper.class,
CustomMeasureMapper.class,
DuplicationMapper.class,
EventMapper.class,
FileSourceMapper.class,
GroupMapper.class,
GroupMembershipMapper.class,
GroupPermissionMapper.class,
InternalPropertiesMapper.class,
IsAliveMapper.class,
IssueChangeMapper.class,
IssueMapper.class,
LoadedTemplateMapper.class,
MeasureMapper.class,
MetricMapper.class,
NotificationQueueMapper.class,
OrganizationMapper.class,
OrganizationMemberMapper.class,
PermissionTemplateCharacteristicMapper.class,
PermissionTemplateMapper.class,
ProjectQgateAssociationMapper.class,
PropertiesMapper.class,
PurgeMapper.class,
QProfileChangeMapper.class,
QualityGateConditionMapper.class,
QualityGateMapper.class,
QualityProfileMapper.class,
RoleMapper.class,
RuleMapper.class,
RuleRepositoryMapper.class,
SchemaMigrationMapper.class,
SnapshotMapper.class,
UserGroupMapper.class,
UserMapper.class,
UserPermissionMapper.class,
UserTokenMapper.class,
WebhookDeliveryMapper.class
};
confBuilder.loadMappers(mappers);
sessionFactory = new SqlSessionFactoryBuilder().build(confBuilder.build());
}
@Override
public void stop() {
// nothing to do
}
@VisibleForTesting
SqlSessionFactory getSessionFactory() {
return sessionFactory;
}
public DbSession openSession(boolean batch) {
if (batch) {
SqlSession session = sessionFactory.openSession(ExecutorType.BATCH);
return new BatchSession(session);
}
SqlSession session = sessionFactory.openSession(ExecutorType.REUSE);
return new DbSession(session);
}
/**
* Create a PreparedStatement for SELECT requests with scrolling of results
*/
public PreparedStatement newScrollingSelectStatement(DbSession session, String sql) {
int fetchSize = database.getDialect().getScrollDefaultFetchSize();
return newScrollingSelectStatement(session, sql, fetchSize);
}
/**
* Create a PreparedStatement for SELECT requests with scrolling of results row by row (only one row
* in memory at a time)
*/
public PreparedStatement newScrollingSingleRowSelectStatement(DbSession session, String sql) {
int fetchSize = database.getDialect().getScrollSingleRowFetchSize();
return newScrollingSelectStatement(session, sql, fetchSize);
}
private static PreparedStatement newScrollingSelectStatement(DbSession session, String sql, int fetchSize) {
try {
PreparedStatement stmt = session.getConnection().prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(fetchSize);
return stmt;
} catch (SQLException e) {
throw new IllegalStateException("Fail to create SQL statement: " + sql, e);
}
}
}