/* * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.buildServer.server.rest.data.investigations; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import jetbrains.buildServer.BuildProject; import jetbrains.buildServer.BuildType; import jetbrains.buildServer.responsibility.*; import jetbrains.buildServer.server.rest.data.*; import jetbrains.buildServer.server.rest.data.problem.ProblemFinder; import jetbrains.buildServer.server.rest.data.problem.ProblemWrapper; import jetbrains.buildServer.server.rest.data.problem.TestFinder; import jetbrains.buildServer.server.rest.errors.BadRequestException; import jetbrains.buildServer.server.rest.errors.InvalidStateException; import jetbrains.buildServer.server.rest.errors.NotFoundException; import jetbrains.buildServer.server.rest.model.PagerData; import jetbrains.buildServer.serverSide.SBuildType; import jetbrains.buildServer.serverSide.SProject; import jetbrains.buildServer.serverSide.STest; import jetbrains.buildServer.users.User; import jetbrains.buildServer.util.CollectionsUtil; import jetbrains.buildServer.util.Converter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * @author Yegor.Yarko * Date: 09.11.13 */ public class InvestigationFinder extends AbstractFinder { private static final String PROBLEM_DIMENSION = "problem"; private static final String TEST_DIMENSION = "test"; private static final String ASSIGNMENT_PROJECT = "assignmentProject"; private static final String AFFECTED_PROJECT = "affectedProject"; private static final String ASSIGNEE = "assignee"; private static final String SINCE_DATE = "sinceDate"; private static final String STATE = "state"; private static final String TYPE = "type"; private static final String REPORTER = "reporter"; private static final String BUILD_TYPE = "buildType"; private final ProjectFinder myProjectFinder; private final BuildTypeFinder myBuildTypeFinder; private final ProblemFinder myProblemFinder; private final TestFinder myTestFinder; private final UserFinder myUserFinder; private final BuildTypeResponsibilityFacade myBuildTypeResponsibilityFacade; private final TestNameResponsibilityFacade myTestNameResponsibilityFacade; private final BuildProblemResponsibilityFacade myBuildProblemResponsibilityFacade; public InvestigationFinder(final ProjectFinder projectFinder, final BuildTypeFinder buildTypeFinder, final ProblemFinder problemFinder, final TestFinder testFinder, final UserFinder userFinder, final BuildTypeResponsibilityFacade buildTypeResponsibilityFacade, final TestNameResponsibilityFacade testNameResponsibilityFacade, final BuildProblemResponsibilityFacade buildProblemResponsibilityFacade) { super(new String[]{ASSIGNEE, REPORTER, TYPE, STATE, SINCE_DATE, ASSIGNMENT_PROJECT, AFFECTED_PROJECT, BUILD_TYPE, TEST_DIMENSION, PROBLEM_DIMENSION, DIMENSION_LOOKUP_LIMIT, PagerData.START, PagerData.COUNT}); myProjectFinder = projectFinder; myBuildTypeFinder = buildTypeFinder; myProblemFinder = problemFinder; myTestFinder = testFinder; myUserFinder = userFinder; myBuildTypeResponsibilityFacade = buildTypeResponsibilityFacade; myTestNameResponsibilityFacade = testNameResponsibilityFacade; myBuildProblemResponsibilityFacade = buildProblemResponsibilityFacade; } @NotNull public static String getLocator(@NotNull final SBuildType buildType) { return Locator.createEmptyLocator().setDimension(BUILD_TYPE, BuildTypeFinder.getLocator(buildType)).getStringRepresentation(); } @NotNull public static String getLocator(@NotNull final ProblemWrapper problem) { return Locator.createEmptyLocator().setDimension(PROBLEM_DIMENSION, ProblemFinder.getLocator(problem)).getStringRepresentation(); } @NotNull public static String getLocator(@NotNull final STest test) { return Locator.createEmptyLocator().setDimension(TEST_DIMENSION, TestFinder.getTestLocator(test)).getStringRepresentation(); } @NotNull public static String getLocator(final InvestigationWrapper investigation) { final Locator result = Locator.createEmptyLocator(); //.setDimension(TYPE, investigation.getType()); if (investigation.isBuildType()) { //noinspection ConstantConditions result.setDimension(BUILD_TYPE, BuildTypeFinder.getLocator((SBuildType)investigation.getBuildTypeRE().getBuildType())); //todo: TeamCity API issue: cast } else if (investigation.isProblem()) { //noinspection ConstantConditions result.setDimension(PROBLEM_DIMENSION, ProblemFinder.getLocator(investigation.getProblemRE().getBuildProblemInfo().getId())); result.setDimension(ASSIGNMENT_PROJECT, ProjectFinder.getLocator(investigation.getProblemRE().getProject())); } else if (investigation.isTest()) { //noinspection ConstantConditions result.setDimension(TEST_DIMENSION, TestFinder.getTestLocator(investigation.getTestRE().getTestNameId())); result.setDimension(ASSIGNMENT_PROJECT, ProjectFinder.getLocator(investigation.getTestRE().getProject())); } else { throw new InvalidStateException("Unknown investigation type"); } return result.getStringRepresentation(); } @Override protected InvestigationWrapper findSingleItem(@NotNull final Locator locator) { return null; } @Override @NotNull public List getAllItems() { return getInvestigationWrappersForProjectWithSubprojects(myProjectFinder.getRootProject(), null); } @Override protected AbstractFilter getFilter(final Locator locator) { if (locator.isSingleValue()) { throw new BadRequestException("Single value locator '" + locator.getSingleValue() + "' is not supported for several items query."); } final Long countFromFilter = locator.getSingleDimensionValueAsLong(PagerData.COUNT); final MultiCheckerFilter result = new MultiCheckerFilter(locator.getSingleDimensionValueAsLong(PagerData.START), countFromFilter != null ? countFromFilter.intValue() : null, locator.getSingleDimensionValueAsLong(DIMENSION_LOOKUP_LIMIT)); final String investigatorDimension = locator.getSingleDimensionValue(ASSIGNEE); if (investigatorDimension != null) { @NotNull final User user = myUserFinder.getUser(investigatorDimension); result.add(new FilterConditionChecker() { public boolean isIncluded(@NotNull final InvestigationWrapper item) { return user.equals(item.getResponsibleUser()); } }); } final String reporterDimension = locator.getSingleDimensionValue(REPORTER); if (reporterDimension != null) { @NotNull final User user = myUserFinder.getUser(reporterDimension); result.add(new FilterConditionChecker() { public boolean isIncluded(@NotNull final InvestigationWrapper item) { return user.equals(item.getReporterUser()); } }); } final String typeDimension = locator.getSingleDimensionValue(TYPE); if (typeDimension != null) { result.add(new FilterConditionChecker() { public boolean isIncluded(@NotNull final InvestigationWrapper item) { return typeDimension.equals(item.getType()); } }); } final String stateDimension = locator.getSingleDimensionValue(STATE); if (stateDimension != null) { result.add(new FilterConditionChecker() { public boolean isIncluded(@NotNull final InvestigationWrapper item) { return stateDimension.equals(item.getState().name()); } }); } final String assignmentProjectDimension = locator.getSingleDimensionValue(ASSIGNMENT_PROJECT); if (assignmentProjectDimension != null){ @NotNull final SProject project = myProjectFinder.getProject(assignmentProjectDimension); result.add(new FilterConditionChecker() { public boolean isIncluded(@NotNull final InvestigationWrapper item) { final BuildProject assignmentProject = item.getAssignmentProject(); return assignmentProject != null && project.getProjectId().equals(assignmentProject.getProjectId()); } }); } final String affectedProjectDimension = locator.getSingleDimensionValue(AFFECTED_PROJECT); if (affectedProjectDimension != null){ @NotNull final SProject project = myProjectFinder.getProject(affectedProjectDimension); result.add(new FilterConditionChecker() { public boolean isIncluded(@NotNull final InvestigationWrapper item) { final BuildProject assignmentProject = item.getAssignmentProject(); final BuildType assignmentBuildType = item.getAssignmentBuildType(); final BuildProject buildTypeProject = assignmentBuildType != null ? myProjectFinder.findProjectByInternalId(assignmentBuildType.getProjectId()) : null; return (assignmentProject != null && ProjectFinder.isSameOrParent(project, assignmentProject)) || (buildTypeProject != null && ProjectFinder.isSameOrParent(project, buildTypeProject)); } }); } final String sinceDateDimension = locator.getSingleDimensionValue(SINCE_DATE); if (sinceDateDimension != null) { final Date date = DataProvider.getDate(sinceDateDimension); result.add(new FilterConditionChecker() { public boolean isIncluded(@NotNull final InvestigationWrapper item) { return date.before(item.getTimestamp()); } }); } //todo: add assignmentBuildType return result; } @Override protected List getPrefilteredItems(@NotNull final Locator locator) { final String problemDimension = locator.getSingleDimensionValue(PROBLEM_DIMENSION); if (problemDimension != null){ final ProblemWrapper problem = myProblemFinder.getItem(problemDimension); return problem.getInvestigations(); } final String testDimension = locator.getSingleDimensionValue(TEST_DIMENSION); if (testDimension != null){ final STest test = myTestFinder.getItem(testDimension); return getInvestigationWrappers(test); } final String buildTypeDimension = locator.getSingleDimensionValue(BUILD_TYPE); if (buildTypeDimension != null){ final SBuildType buildType = myBuildTypeFinder.getBuildType(null, buildTypeDimension, false); return getInvestigationWrappersForBuildType(buildType); } @Nullable User user = null; final String investigatorDimension = locator.getSingleDimensionValue(ASSIGNEE); if (investigatorDimension != null) { user = myUserFinder.getUser(investigatorDimension); } final String assignmentProjectDimension = locator.getSingleDimensionValue(ASSIGNMENT_PROJECT); if (assignmentProjectDimension != null){ @NotNull final SProject project = myProjectFinder.getProject(assignmentProjectDimension); return getInvestigationWrappersForProject(project, user); } final String affectedProjectDimension = locator.getSingleDimensionValue(AFFECTED_PROJECT); if (affectedProjectDimension != null){ @NotNull final SProject project = myProjectFinder.getProject(affectedProjectDimension); return getInvestigationWrappersForProjectWithSubprojects(project, user); } if (user != null){ return getInvestigationWrappersForProjectWithSubprojects(myProjectFinder.getRootProject(), user); } locator.markUnused(ASSIGNEE); return super.getPrefilteredItems(locator); } public List getInvestigationWrappersForBuildType(final SBuildType buildType) { final ResponsibilityEntry responsibilityInfo = buildType.getResponsibilityInfo(); final ResponsibilityEntry.State state = responsibilityInfo.getState(); if (state.equals(ResponsibilityEntry.State.NONE)) { return Collections.emptyList(); } else { return Collections.singletonList(new InvestigationWrapper(getBuildTypeRE(buildType))); } } @NotNull private List getInvestigationWrappersForProjectWithSubprojects(@NotNull final SProject project, @Nullable User user) { if (myProjectFinder.getRootProject().getExternalId().equals(project.getExternalId())){ // this is a root project, use single call return getInvestigationWrappersInternal(null, user); } final ArrayList result = new ArrayList(); result.addAll(getInvestigationWrappersForProject(project, user)); //todo: TeamCity API: is there a dedicated wahy to do this? final List subProjects = project.getProjects(); for (SProject subProject : subProjects) { result.addAll(getInvestigationWrappersForProject(subProject, user)); } return result; } private List getInvestigationWrappersForProject(@NotNull final SProject project, @Nullable User user) { return getInvestigationWrappersInternal(project, user); } /** * * @param project if null, all projects are processed, if not - only the project passed */ private List getInvestigationWrappersInternal(@Nullable final SProject project, @Nullable User user) { final ArrayList result = new ArrayList(); final String projectId = project == null ? null : project.getProjectId(); final List buildTypeResponsibilities = myBuildTypeResponsibilityFacade.getUserBuildTypeResponsibilities(user, projectId); result.addAll(CollectionsUtil.convertCollection(buildTypeResponsibilities, new Converter() { public InvestigationWrapper createFrom(@NotNull final BuildTypeResponsibilityEntry source) { return new InvestigationWrapper(source); } })); final List testResponsibilities = myTestNameResponsibilityFacade.getUserTestNameResponsibilities(user, projectId); result.addAll(CollectionsUtil.convertCollection(testResponsibilities, new Converter() { public InvestigationWrapper createFrom(@NotNull final TestNameResponsibilityEntry source) { return new InvestigationWrapper(source); } })); final List problemResponsibilities = myBuildProblemResponsibilityFacade.getUserBuildProblemResponsibilities(user, projectId); result.addAll(CollectionsUtil.convertCollection(problemResponsibilities, new Converter() { public InvestigationWrapper createFrom(@NotNull final BuildProblemResponsibilityEntry source) { return new InvestigationWrapper(source); } })); //todo: sort! return result; } @NotNull public List getInvestigationWrappers(@NotNull final STest item) { final List responsibilities = item.getAllResponsibilities(); final ArrayList result = new ArrayList(responsibilities.size()); for (TestNameResponsibilityEntry responsibility : responsibilities) { result.add(new InvestigationWrapper(responsibility)); } return result; } private boolean isInvestigationRelatedToProblem(@NotNull final InvestigationWrapper item, @NotNull final ProblemWrapper problem) { if (!item.isProblem()){ return false; } @SuppressWarnings("ConstantConditions") @NotNull final BuildProblemResponsibilityEntry problemRE = item.getProblemRE(); return problemRE.getBuildProblemInfo().getId() == problem.getId(); } public BuildTypeResponsibilityEntry getBuildTypeRE(@NotNull final SBuildType buildType) { //todo: TeamCity API (MP): would be good to use buildType.getResponsibilityInfo() here final List userBuildTypeResponsibilities = myBuildTypeResponsibilityFacade.getUserBuildTypeResponsibilities(null, null); for (BuildTypeResponsibilityEntry responsibility : userBuildTypeResponsibilities) { if (responsibility.getBuildType().equals(buildType)){ return responsibility; } } throw new NotFoundException("Build type with id '" + buildType.getExternalId() + "' does not have associated investigation."); } }