Skip to content

Commit

Permalink
Refactor WS about association of Q profiles and projects
Browse files Browse the repository at this point in the history
- remove class from CE
- do not use multiple DB sessions
- reuse existing code
- load project once
  • Loading branch information
Simon Brandhof committed Jan 23, 2017
1 parent 2a980a5 commit 8b7326e
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 272 deletions.
Expand Up @@ -122,7 +122,6 @@
import org.sonar.server.plugins.privileged.PrivilegedPluginsStopper; import org.sonar.server.plugins.privileged.PrivilegedPluginsStopper;
import org.sonar.server.property.InternalPropertiesImpl; import org.sonar.server.property.InternalPropertiesImpl;
import org.sonar.server.qualityprofile.QProfileLookup; import org.sonar.server.qualityprofile.QProfileLookup;
import org.sonar.server.qualityprofile.QProfileProjectOperations;
import org.sonar.server.qualityprofile.index.ActiveRuleIndex; import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.rule.CommonRuleDefinitionsImpl; import org.sonar.server.rule.CommonRuleDefinitionsImpl;
Expand Down Expand Up @@ -303,7 +302,6 @@ private static Object[] level4Components() {
AnnotationProfileParser.class, AnnotationProfileParser.class,
Rules.QProfiles.class, Rules.QProfiles.class,
QProfileLookup.class, QProfileLookup.class,
QProfileProjectOperations.class,


// rule // rule
RuleIndexer.class, RuleIndexer.class,
Expand Down
Expand Up @@ -88,7 +88,7 @@ public void real_start() throws IOException {
assertThat(picoContainer.getComponentAdapters()) assertThat(picoContainer.getComponentAdapters())
.hasSize( .hasSize(
CONTAINER_ITSELF CONTAINER_ITSELF
+ 78 // level 4 + 77 // level 4
+ 4 // content of CeConfigurationModule + 4 // content of CeConfigurationModule
+ 3 // content of CeHttpModule + 3 // content of CeHttpModule
+ 5 // content of CeQueueModule + 5 // content of CeQueueModule
Expand Down
Expand Up @@ -19,127 +19,68 @@
*/ */
package org.sonar.server.qualityprofile; package org.sonar.server.qualityprofile;


import javax.annotation.Nullable;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.server.ServerSide; import org.sonar.api.server.ServerSide;
import org.sonar.api.web.UserRole; import org.sonar.api.web.UserRole;
import org.sonar.core.permission.GlobalPermissions; import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
import org.sonar.db.MyBatis;
import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentDto;
import org.sonar.db.qualityprofile.QualityProfileDto; import org.sonar.db.qualityprofile.QualityProfileDto;
import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.user.UserSession; import org.sonar.server.user.UserSession;
import org.sonar.server.ws.WsUtils;


/** /**
* Should be refactored in order to use project key. Maybe should it be move to {@link QProfileFactory} * Should be refactored in order to use project key. Maybe should it be move to {@link QProfileFactory}
* Permission checks should also be done in the upper service. * Permission checks should also be done in the upper service.
*/ */
@ServerSide @ServerSide
@ComputeEngineSide
public class QProfileProjectOperations { public class QProfileProjectOperations {


private final DbClient db; private final DbClient db;
private final UserSession userSession;


public QProfileProjectOperations(DbClient db) { public QProfileProjectOperations(DbClient db, UserSession userSession) {
this.db = db; this.db = db;
this.userSession = userSession;
} }


public void addProject(String profileKey, String projectUuid, UserSession userSession) { public void addProject(DbSession dbSession, String profileKey, ComponentDto project) {
DbSession session = db.openSession(false); checkAdminOnProject(project.key());
try { QualityProfileDto qualityProfile = selectProfileByKey(dbSession, profileKey);
addProject(profileKey, projectUuid, userSession, session);
session.commit();
} finally {
MyBatis.closeQuietly(session);
}
}


private void addProject(String profileKey, String projectUuid, UserSession userSession, DbSession session) { QualityProfileDto currentProfile = db.qualityProfileDao().selectByProjectAndLanguage(dbSession, project.key(), qualityProfile.getLanguage());
ComponentDto project = db.componentDao().selectOrFailByUuid(session, projectUuid);
checkPermission(userSession, project.key());
QualityProfileDto qualityProfile = findNotNull(profileKey, session);

QualityProfileDto currentProfile = db.qualityProfileDao().selectByProjectAndLanguage(session, project.key(), qualityProfile.getLanguage());


boolean updated = false; boolean updated = false;
if (currentProfile == null) { if (currentProfile == null) {
db.qualityProfileDao().insertProjectProfileAssociation(project.uuid(), qualityProfile.getKey(), session); db.qualityProfileDao().insertProjectProfileAssociation(project.uuid(), qualityProfile.getKey(), dbSession);
updated = true; updated = true;
} else if (!profileKey.equals(currentProfile.getKey())) { } else if (!profileKey.equals(currentProfile.getKey())) {
db.qualityProfileDao().updateProjectProfileAssociation(projectUuid, profileKey, currentProfile.getKey(), session); db.qualityProfileDao().updateProjectProfileAssociation(project.uuid(), profileKey, currentProfile.getKey(), dbSession);
updated = true; updated = true;
} }
if (updated) { if (updated) {
session.commit(); dbSession.commit();
}
}

public void removeProject(String profileKey, String projectUuid, UserSession userSession) {
DbSession session = db.openSession(false);
try {
ComponentDto project = db.componentDao().selectOrFailByUuid(session, projectUuid);
checkPermission(userSession, project.key());
QualityProfileDto qualityProfile = findNotNull(profileKey, session);

db.qualityProfileDao().deleteProjectProfileAssociation(project.uuid(), qualityProfile.getKey(), session);
session.commit();
} finally {
MyBatis.closeQuietly(session);
}
}

void removeProject(String language, long projectId, UserSession userSession) {
DbSession session = db.openSession(false);
try {
ComponentDto project = db.componentDao().selectOrFailById(session, projectId);
checkPermission(userSession, project.key());

QualityProfileDto associatedProfile = db.qualityProfileDao().selectByProjectAndLanguage(session, project.getKey(), language);
if (associatedProfile != null) {
db.qualityProfileDao().deleteProjectProfileAssociation(project.uuid(), associatedProfile.getKey(), session);
session.commit();
}
} finally {
MyBatis.closeQuietly(session);
} }
} }


void removeAllProjects(String profileKey, UserSession userSession) { public void removeProject(DbSession dbSession, String profileKey, ComponentDto project) {
checkPermission(userSession); checkAdminOnProject(project.key());
DbSession session = db.openSession(false); QualityProfileDto qualityProfile = selectProfileByKey(dbSession, profileKey);
try {
QualityProfileDto qualityProfile = findNotNull(profileKey, session);
db.qualityProfileDao().deleteAllProjectProfileAssociation(qualityProfile.getKey(), session);
session.commit();
} finally {
MyBatis.closeQuietly(session);
}
}


private QualityProfileDto findNotNull(String key, DbSession session) { db.qualityProfileDao().deleteProjectProfileAssociation(project.uuid(), qualityProfile.getKey(), dbSession);
QualityProfileDto qualityProfile = db.qualityProfileDao().selectByKey(session, key); dbSession.commit();
checkProfileIsNotNull(qualityProfile);
return qualityProfile;
} }


private static void checkPermission(UserSession userSession) { private QualityProfileDto selectProfileByKey(DbSession session, String profileKey) {
userSession.checkPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN); QualityProfileDto qualityProfile = db.qualityProfileDao().selectByKey(session, profileKey);
return WsUtils.checkFound(qualityProfile, "Quality profile does not exist");
} }


private static void checkPermission(UserSession userSession, String projectKey) { private void checkAdminOnProject(String projectKey) {
if (!userSession.hasPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN) && !userSession.hasComponentPermission(UserRole.ADMIN, projectKey)) { if (!userSession.hasPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN) && !userSession.hasComponentPermission(UserRole.ADMIN, projectKey)) {
throw new ForbiddenException("Insufficient privileges"); throw new ForbiddenException("Insufficient privileges");
} }
} }


private static QualityProfileDto checkProfileIsNotNull(@Nullable QualityProfileDto profile) {
if (profile == null) {
throw new NotFoundException("This quality profile does not exists.");
}
return profile;
}

} }
Expand Up @@ -23,8 +23,10 @@
import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.NewAction; import org.sonar.api.server.ws.WebService.NewAction;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.server.qualityprofile.QProfileProjectOperations; import org.sonar.server.qualityprofile.QProfileProjectOperations;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.client.qualityprofile.AddProjectRequest; import org.sonarqube.ws.client.qualityprofile.AddProjectRequest;


import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_ADD_PROJECT; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_ADD_PROJECT;
Expand All @@ -39,14 +41,14 @@ public class AddProjectAction implements QProfileWsAction {
private final ProjectAssociationParameters projectAssociationParameters; private final ProjectAssociationParameters projectAssociationParameters;
private final ProjectAssociationFinder projectAssociationFinder; private final ProjectAssociationFinder projectAssociationFinder;
private final QProfileProjectOperations profileProjectOperations; private final QProfileProjectOperations profileProjectOperations;
private final UserSession userSession; private final DbClient dbClient;


public AddProjectAction(ProjectAssociationParameters projectAssociationParameters, QProfileProjectOperations profileProjectOperations, public AddProjectAction(ProjectAssociationParameters projectAssociationParameters, QProfileProjectOperations profileProjectOperations,
ProjectAssociationFinder projectAssociationFinder, UserSession userSession) { ProjectAssociationFinder projectAssociationFinder, DbClient dbClient) {
this.projectAssociationParameters = projectAssociationParameters; this.projectAssociationParameters = projectAssociationParameters;
this.profileProjectOperations = profileProjectOperations; this.profileProjectOperations = profileProjectOperations;
this.projectAssociationFinder = projectAssociationFinder; this.projectAssociationFinder = projectAssociationFinder;
this.userSession = userSession; this.dbClient = dbClient;
} }


@Override @Override
Expand All @@ -61,9 +63,13 @@ public void define(WebService.NewController controller) {
@Override @Override
public void handle(Request request, Response response) throws Exception { public void handle(Request request, Response response) throws Exception {
AddProjectRequest addProjectRequest = toWsRequest(request); AddProjectRequest addProjectRequest = toWsRequest(request);
String profileKey = projectAssociationFinder.getProfileKey(addProjectRequest.getLanguage(), addProjectRequest.getProfileName(), addProjectRequest.getProfileKey());
String projectUuid = projectAssociationFinder.getProjectUuid(addProjectRequest.getProjectKey(), addProjectRequest.getProjectUuid()); try (DbSession dbSession = dbClient.openSession(false)) {
profileProjectOperations.addProject(profileKey, projectUuid, userSession); String profileKey = projectAssociationFinder.getProfileKey(addProjectRequest.getLanguage(), addProjectRequest.getProfileName(), addProjectRequest.getProfileKey());
ComponentDto project = projectAssociationFinder.getProject(dbSession, addProjectRequest.getProjectKey(), addProjectRequest.getProjectUuid());
profileProjectOperations.addProject(dbSession, profileKey, project);
}

response.noContent(); response.noContent();
} }


Expand Down
Expand Up @@ -20,7 +20,9 @@
package org.sonar.server.qualityprofile.ws; package org.sonar.server.qualityprofile.ws;


import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.sonar.server.component.ComponentService; import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.qualityprofile.QProfile; import org.sonar.server.qualityprofile.QProfile;
import org.sonar.server.qualityprofile.QProfileLookup; import org.sonar.server.qualityprofile.QProfileLookup;
Expand All @@ -31,24 +33,22 @@
public class ProjectAssociationFinder { public class ProjectAssociationFinder {


private static final String BAD_PROFILE_PARAMETERS_ERROR = "Either profileKey or profileName + language must be set"; private static final String BAD_PROFILE_PARAMETERS_ERROR = "Either profileKey or profileName + language must be set";
private static final String BAD_PROJECT_PARAMETERS_ERROR = "Either projectKey or projectUuid must be set";


private final QProfileLookup profileLookup; private final QProfileLookup profileLookup;
private final ComponentService componentService; private final ComponentFinder componentFinder;


public ProjectAssociationFinder(QProfileLookup profileLookup, ComponentService componentService) { public ProjectAssociationFinder(QProfileLookup profileLookup, ComponentFinder componentFinder) {
this.profileLookup = profileLookup; this.profileLookup = profileLookup;
this.componentService = componentService; this.componentFinder = componentFinder;
} }


public String getProfileKey(@Nullable String language, @Nullable String profileName, @Nullable String profileKey) { public String getProfileKey(@Nullable String language, @Nullable String profileName, @Nullable String profileKey) {
checkArgument((!isEmpty(language) && !isEmpty(profileName)) ^ !isEmpty(profileKey), BAD_PROFILE_PARAMETERS_ERROR); checkArgument((!isEmpty(language) && !isEmpty(profileName)) ^ !isEmpty(profileKey), BAD_PROFILE_PARAMETERS_ERROR);
return profileKey == null ? getProfileKeyFromLanguageAndName(language, profileName) : profileKey; return profileKey == null ? getProfileKeyFromLanguageAndName(language, profileName) : profileKey;
} }


public String getProjectUuid(@Nullable String projectKey, @Nullable String projectUuid) { public ComponentDto getProject(DbSession dbSession, @Nullable String projectKey, @Nullable String projectUuid) {
checkArgument(!isEmpty(projectKey) ^ !isEmpty(projectUuid), BAD_PROJECT_PARAMETERS_ERROR); return componentFinder.getByUuidOrKey(dbSession, projectUuid, projectKey, ComponentFinder.ParamNames.PROJECT_UUID_AND_KEY);
return projectUuid == null ? componentService.getByKey(projectKey).uuid() : projectUuid;
} }


private String getProfileKeyFromLanguageAndName(String language, String profileName) { private String getProfileKeyFromLanguageAndName(String language, String profileName) {
Expand Down
Expand Up @@ -23,8 +23,10 @@
import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.NewAction; import org.sonar.api.server.ws.WebService.NewAction;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.server.qualityprofile.QProfileProjectOperations; import org.sonar.server.qualityprofile.QProfileProjectOperations;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.client.qualityprofile.RemoveProjectRequest; import org.sonarqube.ws.client.qualityprofile.RemoveProjectRequest;


import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_REMOVE_PROJECT; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_REMOVE_PROJECT;
Expand All @@ -39,14 +41,14 @@ public class RemoveProjectAction implements QProfileWsAction {
private final ProjectAssociationParameters projectAssociationParameters; private final ProjectAssociationParameters projectAssociationParameters;
private final ProjectAssociationFinder projectAssociationFinder; private final ProjectAssociationFinder projectAssociationFinder;
private final QProfileProjectOperations profileProjectOperations; private final QProfileProjectOperations profileProjectOperations;
private final UserSession userSession; private final DbClient dbClient;


public RemoveProjectAction(ProjectAssociationParameters projectAssociationParameters, ProjectAssociationFinder projectAssociationFinder, public RemoveProjectAction(ProjectAssociationParameters projectAssociationParameters, ProjectAssociationFinder projectAssociationFinder,
QProfileProjectOperations profileProjectOperations, UserSession userSession) { QProfileProjectOperations profileProjectOperations, DbClient dbClient) {
this.projectAssociationParameters = projectAssociationParameters; this.projectAssociationParameters = projectAssociationParameters;
this.projectAssociationFinder = projectAssociationFinder; this.projectAssociationFinder = projectAssociationFinder;
this.profileProjectOperations = profileProjectOperations; this.profileProjectOperations = profileProjectOperations;
this.userSession = userSession; this.dbClient = dbClient;
} }


@Override @Override
Expand All @@ -61,9 +63,11 @@ public void define(WebService.NewController controller) {
@Override @Override
public void handle(Request request, Response response) throws Exception { public void handle(Request request, Response response) throws Exception {
RemoveProjectRequest removeProjectRequest = toWsRequest(request); RemoveProjectRequest removeProjectRequest = toWsRequest(request);
String profileKey = projectAssociationFinder.getProfileKey(removeProjectRequest.getLanguage(), removeProjectRequest.getProfileName(), removeProjectRequest.getProfileKey()); try (DbSession dbSession = dbClient.openSession(false)) {
String projectUuid = projectAssociationFinder.getProjectUuid(removeProjectRequest.getProjectKey(), removeProjectRequest.getProjectUuid()); String profileKey = projectAssociationFinder.getProfileKey(removeProjectRequest.getLanguage(), removeProjectRequest.getProfileName(), removeProjectRequest.getProfileKey());
profileProjectOperations.removeProject(profileKey, projectUuid, userSession); ComponentDto project = projectAssociationFinder.getProject(dbSession, removeProjectRequest.getProjectKey(), removeProjectRequest.getProjectUuid());
profileProjectOperations.removeProject(dbSession, profileKey, project);
}
response.noContent(); response.noContent();
} }


Expand Down

0 comments on commit 8b7326e

Please sign in to comment.