org.sonar.db.component.ResourceIndexDao Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sonar-db Show documentation
Show all versions of sonar-db Show documentation
Create and request SonarQube schema
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.component;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.SqlSession;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.System2;
import org.sonar.db.AbstractDao;
import org.sonar.db.DbSession;
import org.sonar.db.MyBatis;
public class ResourceIndexDao extends AbstractDao {
private static final String SELECT_RESOURCES = "org.sonar.db.component.ResourceIndexMapper.selectResources";
public static final int MINIMUM_KEY_SIZE = 3;
public static final int SINGLE_INDEX_SIZE = 2;
// The scopes and qualifiers that are not in the following constants are not indexed at all.
// Directories and packages are explicitly excluded.
private static final String[] RENAMABLE_QUALIFIERS = {Qualifiers.PROJECT, Qualifiers.MODULE, Qualifiers.VIEW, Qualifiers.SUBVIEW};
private static final String[] RENAMABLE_SCOPES = {Scopes.PROJECT};
private static final String[] NOT_RENAMABLE_QUALIFIERS = {Qualifiers.FILE, Qualifiers.UNIT_TEST_FILE, Qualifiers.CLASS};
private static final String[] NOT_RENAMABLE_SCOPES = {Scopes.FILE};
public ResourceIndexDao(MyBatis myBatis, System2 system2) {
super(myBatis, system2);
}
public List selectProjectIdsFromQueryAndViewOrSubViewUuid(DbSession session, String query, String viewOrSubViewUuid) {
return session.getMapper(ResourceIndexMapper.class).selectProjectIdsFromQueryAndViewOrSubViewUuid(query + "%", "%." + viewOrSubViewUuid + ".%");
}
/**
* This method is reentrant. It can be executed even if the project is already indexed.
*/
public ResourceIndexDao indexProject(final long rootProjectId) {
DbSession session = myBatis().openSession(true);
try {
indexProject(rootProjectId, session);
session.commit();
return this;
} finally {
MyBatis.closeQuietly(session);
}
}
public void indexProject(final long rootProjectId, DbSession session) {
ResourceIndexMapper mapper = session.getMapper(ResourceIndexMapper.class);
doIndexProject(rootProjectId, session, mapper);
}
/**
* This method is reentrant. It can be executed even if some projects are already indexed.
*/
public ResourceIndexDao indexProjects() {
final DbSession session = myBatis().openSession(true);
try {
final ResourceIndexMapper mapper = session.getMapper(ResourceIndexMapper.class);
session.select(ResourceIndexMapper.class.getName() + ".selectRootProjectIds", /* workaround to get booleans */ResourceIndexQuery.create(), new ResultHandler() {
@Override
public void handleResult(ResultContext context) {
Integer rootProjectId = (Integer) context.getResultObject();
doIndexProject(rootProjectId, session, mapper);
session.commit();
}
});
return this;
} finally {
MyBatis.closeQuietly(session);
}
}
private void doIndexProject(long rootProjectId, SqlSession session, final ResourceIndexMapper mapper) {
// non indexed resources
ResourceIndexQuery query = ResourceIndexQuery.create()
.setNonIndexedOnly(true)
.setQualifiers(NOT_RENAMABLE_QUALIFIERS)
.setScopes(NOT_RENAMABLE_SCOPES)
.setRootProjectId(rootProjectId);
session.select(SELECT_RESOURCES, query, new ResultHandler() {
@Override
public void handleResult(ResultContext context) {
ResourceDto resource = (ResourceDto) context.getResultObject();
doIndex(resource, mapper);
}
});
// some resources can be renamed, so index must be regenerated
// -> delete existing rows and create them again
query = ResourceIndexQuery.create()
.setNonIndexedOnly(false)
.setQualifiers(RENAMABLE_QUALIFIERS)
.setScopes(RENAMABLE_SCOPES)
.setRootProjectId(rootProjectId);
session.select(SELECT_RESOURCES, query, new ResultHandler() {
@Override
public void handleResult(ResultContext context) {
ResourceDto resource = (ResourceDto) context.getResultObject();
mapper.deleteByResourceId(resource.getId());
doIndex(resource, mapper);
}
});
}
void doIndex(ResourceDto resource, ResourceIndexMapper mapper) {
String key = nameToKey(resource.getName());
if (key.length() >= MINIMUM_KEY_SIZE || key.length() == SINGLE_INDEX_SIZE) {
insertIndexEntries(key, resource.getId(), resource.getQualifier(), resource.getRootId(), resource.getName().length(), mapper);
}
}
public boolean indexResource(long id) {
DbSession session = myBatis().openSession(false);
try {
return indexResource(session, id);
} finally {
MyBatis.closeQuietly(session);
}
}
public boolean indexResource(DbSession session, long id) {
boolean indexed = false;
ResourceIndexMapper mapper = session.getMapper(ResourceIndexMapper.class);
ResourceDto resource = mapper.selectResourceToIndex(id);
if (resource != null) {
Long rootId = resource.getRootId();
if (rootId == null) {
rootId = resource.getId();
}
indexed = indexResource(resource.getId(), resource.getName(), resource.getQualifier(), rootId, session, mapper);
}
return indexed;
}
public boolean indexResource(int id, String name, String qualifier, int rootId) {
boolean indexed = false;
SqlSession session = myBatis().openSession(false);
ResourceIndexMapper mapper = session.getMapper(ResourceIndexMapper.class);
try {
indexed = indexResource(id, name, qualifier, rootId, session, mapper);
} finally {
MyBatis.closeQuietly(session);
}
return indexed;
}
private static boolean indexResource(long id, String name, String qualifier, long rootId, SqlSession session, ResourceIndexMapper mapper) {
boolean indexed = false;
String key = nameToKey(name);
if (key.length() >= MINIMUM_KEY_SIZE || key.length() == SINGLE_INDEX_SIZE) {
indexed = true;
boolean toBeIndexed = sanitizeIndex(id, key, mapper);
if (toBeIndexed) {
insertIndexEntries(key, id, qualifier, rootId, name.length(), mapper);
session.commit();
}
}
return indexed;
}
private static void insertIndexEntries(String key, long resourceId, String qualifier, long rootId, int nameLength, ResourceIndexMapper mapper) {
ResourceIndexDto dto = new ResourceIndexDto()
.setResourceId(resourceId)
.setQualifier(qualifier)
.setRootProjectId(rootId)
.setNameSize(nameLength);
int maxPosition = key.length() == SINGLE_INDEX_SIZE ? 0 : key.length() - MINIMUM_KEY_SIZE;
for (int position = 0; position <= maxPosition; position++) {
dto.setPosition(position);
dto.setKey(StringUtils.substring(key, position));
mapper.insert(dto);
}
}
/**
* Return true if the resource must be indexed, false if the resource is already indexed.
* If the resource is indexed with a different key, then this index is dropped and the
* resource must be indexed again.
*/
private static boolean sanitizeIndex(long resourceId, String key, ResourceIndexMapper mapper) {
ResourceIndexDto masterIndex = mapper.selectMasterIndexByResourceId(resourceId);
if (masterIndex != null && !StringUtils.equals(key, masterIndex.getKey())) {
// resource has been renamed -> drop existing indexes
mapper.deleteByResourceId(resourceId);
masterIndex = null;
}
return masterIndex == null;
}
static String nameToKey(String input) {
return StringUtils.lowerCase(StringUtils.trimToEmpty(input));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy