EMMA Coverage Report (generated Sun Sep 18 11:34:27 PHT 2011)
[all classes][org.apache.maven.continuum]

COVERAGE SUMMARY FOR SOURCE FILE [DefaultContinuum.java]

nameclass, %method, %block, %line, %
DefaultContinuum.java100% (2/2)42%  (70/167)35%  (1810/5140)37%  (435.8/1191)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DefaultContinuum100% (1/1)41%  (68/165)35%  (1800/5130)36%  (432.8/1188)
activePurgeSchedule (Schedule): void 0%   (0/1)0%   (0/11)0%   (0/5)
addBuildDefinitionToProjectGroup (int, BuildDefinition): BuildDefinition 0%   (0/1)0%   (0/23)0%   (0/7)
addBuildQueue (BuildQueue): BuildQueue 0%   (0/1)0%   (0/12)0%   (0/3)
addMavenOneProject (String, int): ContinuumProjectBuildingResult 0%   (0/1)0%   (0/6)0%   (0/1)
addMavenOneProject (String, int, boolean): ContinuumProjectBuildingResult 0%   (0/1)0%   (0/7)0%   (0/1)
addMavenOneProject (String, int, boolean, boolean): ContinuumProjectBuildingR... 0%   (0/1)0%   (0/19)0%   (0/3)
addMavenOneProject (String, int, boolean, boolean, int): ContinuumProjectBuil... 0%   (0/1)0%   (0/10)0%   (0/1)
addMavenTwoProject (String, int): ContinuumProjectBuildingResult 0%   (0/1)0%   (0/6)0%   (0/1)
addMavenTwoProject (String, int, boolean): ContinuumProjectBuildingResult 0%   (0/1)0%   (0/7)0%   (0/1)
addMavenTwoProject (String, int, boolean, boolean): ContinuumProjectBuildingR... 0%   (0/1)0%   (0/21)0%   (0/3)
addMavenTwoProject (String, int, boolean, boolean, boolean): ContinuumProject... 0%   (0/1)0%   (0/21)0%   (0/3)
addSchedule (Schedule): void 0%   (0/1)0%   (0/41)0%   (0/9)
buildProject (int): void 0%   (0/1)0%   (0/5)0%   (0/2)
buildProject (int, int, int): void 0%   (0/1)0%   (0/75)0%   (0/13)
buildProjectGroup (int): void 0%   (0/1)0%   (0/14)0%   (0/4)
buildProjectGroupWithBuildDefinition (int, List, boolean): void 0%   (0/1)0%   (0/18)0%   (0/4)
buildProjectGroupWithBuildDefinition (int, int): void 0%   (0/1)0%   (0/24)0%   (0/7)
buildProjectWithBuildDefinition (int, int): void 0%   (0/1)0%   (0/6)0%   (0/2)
buildProjects (): void 0%   (0/1)0%   (0/4)0%   (0/2)
buildProjects (Schedule): void 0%   (0/1)0%   (0/164)0%   (0/33)
buildProjects (int): void 0%   (0/1)0%   (0/14)0%   (0/4)
buildProjectsWithBuildDefinition (List, List): void 0%   (0/1)0%   (0/11)0%   (0/3)
buildProjectsWithBuildDefinition (List, int): void 0%   (0/1)0%   (0/10)0%   (0/3)
checkoutProject (int): void 0%   (0/1)0%   (0/29)0%   (0/9)
getAllBuildQueues (): List 0%   (0/1)0%   (0/11)0%   (0/3)
getAllProjectGroupsWithBuildDetails (): List 0%   (0/1)0%   (0/4)0%   (0/1)
getAllProjectGroupsWithRepository (int): List 0%   (0/1)0%   (0/5)0%   (0/1)
getBuildDefinition (int, int): BuildDefinition 0%   (0/1)0%   (0/26)0%   (0/7)
getBuildDefinitionService (): BuildDefinitionService 0%   (0/1)0%   (0/3)0%   (0/1)
getBuildDefinitions (int): List 0%   (0/1)0%   (0/7)0%   (0/2)
getBuildDefinitionsForProject (int): List 0%   (0/1)0%   (0/7)0%   (0/2)
getBuildDefinitionsForProjectGroup (int): List 0%   (0/1)0%   (0/7)0%   (0/2)
getBuildOutput (int, int): String 0%   (0/1)0%   (0/12)0%   (0/3)
getBuildQueue (int): BuildQueue 0%   (0/1)0%   (0/12)0%   (0/3)
getBuildQueueByName (String): BuildQueue 0%   (0/1)0%   (0/12)0%   (0/3)
getBuildResult (int): BuildResult 0%   (0/1)0%   (0/11)0%   (0/3)
getBuildResultByBuildNumber (int, int): BuildResult 0%   (0/1)0%   (0/16)0%   (0/2)
getBuildResultsInSuccess (int): Map 0%   (0/1)0%   (0/13)0%   (0/4)
getContinuumReleaseResult (int, String, long, long): ContinuumReleaseResult 0%   (0/1)0%   (0/26)0%   (0/3)
getDefaultBuildDefinitionsForProjectGroup (int): List 0%   (0/1)0%   (0/35)0%   (0/5)
getDistributedBuildManager (): DistributedBuildManager 0%   (0/1)0%   (0/3)0%   (0/1)
getDistributedReleaseManager (): DistributedReleaseManager 0%   (0/1)0%   (0/3)0%   (0/1)
getFileContent (int, String, String): String 0%   (0/1)0%   (0/54)0%   (0/12)
getFiles (File, String, String): List 0%   (0/1)0%   (0/86)0%   (0/16)
getFiles (int, String): List 0%   (0/1)0%   (0/10)0%   (0/2)
getGroupNotifier (int, int): ProjectNotifier 0%   (0/1)0%   (0/29)0%   (0/8)
getLatestBuildResultForProject (int): BuildResult 0%   (0/1)0%   (0/5)0%   (0/1)
getLatestBuildResults (int): Map 0%   (0/1)0%   (0/13)0%   (0/4)
getNbBuildResultsForProject (int): long 0%   (0/1)0%   (0/5)0%   (0/1)
getNotifier (int, int): ProjectNotifier 0%   (0/1)0%   (0/29)0%   (0/8)
getProfileService (): ProfileService 0%   (0/1)0%   (0/3)0%   (0/1)
getProjectGroup (int): ProjectGroup 0%   (0/1)0%   (0/19)0%   (0/5)
getProjectGroupByGroupIdWithBuildDetails (String): ProjectGroup 0%   (0/1)0%   (0/19)0%   (0/5)
getProjectScmRoot (int): ProjectScmRoot 0%   (0/1)0%   (0/25)0%   (0/5)
getProjectScmRootByProjectGroupAndScmRootAddress (int, String): ProjectScmRoot 0%   (0/1)0%   (0/20)0%   (0/3)
getProjectWithBuilds (int): Project 0%   (0/1)0%   (0/19)0%   (0/5)
getProjectWithCheckoutResult (int): Project 0%   (0/1)0%   (0/19)0%   (0/5)
getProjects (): Collection 0%   (0/1)0%   (0/4)0%   (0/1)
getProjectsInBuildOrder (): List 0%   (0/1)0%   (0/5)0%   (0/1)
getProjectsInGroupWithDependencies (int): Collection 0%   (0/1)0%   (0/19)0%   (0/5)
getProjectsNotInReleaseStage (Collection): Collection 0%   (0/1)0%   (0/39)0%   (0/6)
getProjectsSummaryByGroups (): Map 0%   (0/1)0%   (0/4)0%   (0/1)
getProjectsWithDependencies (): Collection 0%   (0/1)0%   (0/4)0%   (0/1)
getPurgeConfigurationService (): PurgeConfigurationService 0%   (0/1)0%   (0/3)0%   (0/1)
getPurgeManager (): ContinuumPurgeManager 0%   (0/1)0%   (0/3)0%   (0/1)
getReleaseManager (): ContinuumReleaseManager 0%   (0/1)0%   (0/3)0%   (0/1)
getReleaseOutput (int): String 0%   (0/1)0%   (0/35)0%   (0/5)
getRepositoryService (): RepositoryService 0%   (0/1)0%   (0/3)0%   (0/1)
getSchedule (int): Schedule 0%   (0/1)0%   (0/11)0%   (0/3)
getScheduleByName (String): Schedule 0%   (0/1)0%   (0/11)0%   (0/3)
getSchedules (): Collection 0%   (0/1)0%   (0/4)0%   (0/1)
getTaskQueueManager (): TaskQueueManager 0%   (0/1)0%   (0/3)0%   (0/1)
prepareBuildProjects (Collection, List, boolean, int): void 0%   (0/1)0%   (0/191)0%   (0/42)
prepareBuildProjects (Collection, int, int): void 0%   (0/1)0%   (0/105)0%   (0/23)
prepareBuildProjects (Map, int, List): void 0%   (0/1)0%   (0/26)0%   (0/3)
prepareBuildProjects (Map, int, String, int, int): void 0%   (0/1)0%   (0/37)0%   (0/8)
reloadConfiguration (): void 0%   (0/1)0%   (0/12)0%   (0/5)
removeBuildDefinition (int, int): void 0%   (0/1)0%   (0/18)0%   (0/6)
removeBuildDefinitionFromProjectGroup (int, int): void 0%   (0/1)0%   (0/17)0%   (0/5)
removeBuildQueue (BuildQueue): void 0%   (0/1)0%   (0/13)0%   (0/5)
removeBuildResult (int): void 0%   (0/1)0%   (0/68)0%   (0/16)
removeGroupNotifier (int, int): void 0%   (0/1)0%   (0/38)0%   (0/12)
removeNotifier (int, int): void 0%   (0/1)0%   (0/29)0%   (0/9)
removeSchedule (int): void 0%   (0/1)0%   (0/43)0%   (0/15)
startup (): void 0%   (0/1)0%   (0/12)0%   (0/5)
stop (): void 0%   (0/1)0%   (0/3)0%   (0/2)
storeBuildQueue (BuildQueue): BuildQueue 0%   (0/1)0%   (0/12)0%   (0/3)
storeNotifier (ProjectNotifier): ProjectNotifier 0%   (0/1)0%   (0/11)0%   (0/3)
storeSchedule (Schedule): Schedule 0%   (0/1)0%   (0/11)0%   (0/3)
updateBuildDefinitionForProject (int, BuildDefinition): BuildDefinition 0%   (0/1)0%   (0/23)0%   (0/7)
updateGroupNotifier (int, ProjectNotifier): ProjectNotifier 0%   (0/1)0%   (0/30)0%   (0/8)
updateNotifier (int, ProjectNotifier): ProjectNotifier 0%   (0/1)0%   (0/21)0%   (0/5)
updateProjectGroup (ProjectGroup): void 0%   (0/1)0%   (0/17)0%   (0/6)
updateProjectScmRoot (ProjectScmRoot, Project): void 0%   (0/1)0%   (0/59)0%   (0/13)
updateSchedule (Schedule): void 0%   (0/1)0%   (0/5)0%   (0/2)
updateSchedule (Schedule, boolean): void 0%   (0/1)0%   (0/37)0%   (0/11)
updateSchedule (int, Map): void 0%   (0/1)0%   (0/42)0%   (0/8)
getContinuumReleaseResult (int): ContinuumReleaseResult 100% (1/1)16%  (5/32)20%  (1/5)
initialize (): void 100% (1/1)19%  (43/226)21%  (8.1/38)
getDefaultBuildDefinition (int): BuildDefinition 100% (1/1)19%  (5/26)20%  (1/5)
buildProject (int, int): void 100% (1/1)23%  (22/97)19%  (3/16)
getProjectWithBuildDetails (int): Project 100% (1/1)25%  (5/20)33%  (1/3)
executeAction (String, Map): void 100% (1/1)25%  (13/51)50%  (6/12)
getBuildDefinition (int): BuildDefinition 100% (1/1)26%  (5/19)20%  (1/5)
getProjectGroupWithBuildDetails (int): ProjectGroup 100% (1/1)26%  (5/19)20%  (1/5)
getProjectWithAllDetails (int): Project 100% (1/1)26%  (5/19)20%  (1/5)
getProjectsInGroup (int): Collection 100% (1/1)26%  (5/19)20%  (1/5)
getProjectGroupByProjectId (int): ProjectGroup 100% (1/1)28%  (5/18)33%  (1/3)
getProjectGroupWithProjects (int): ProjectGroup 100% (1/1)28%  (5/18)33%  (1/3)
start (): void 100% (1/1)37%  (15/41)47%  (7/15)
removeProjectScmRoot (ProjectScmRoot): void 100% (1/1)40%  (41/102)59%  (10.7/18)
addContinuumReleaseResult (ContinuumReleaseResult): ContinuumReleaseResult 100% (1/1)42%  (5/12)33%  (1/3)
createProjectScmRootForProjectGroup (ProjectGroup): void 100% (1/1)45%  (17/38)53%  (3.7/7)
removeContinuumReleaseResult (int): void 100% (1/1)47%  (37/79)65%  (11/17)
logAndCreateException (String, Throwable): ContinuumException 100% (1/1)47%  (9/19)50%  (2/4)
updateProject (Project): void 100% (1/1)51%  (55/108)50%  (13.9/28)
getVersion (): String 100% (1/1)52%  (25/48)56%  (6.8/12)
getWorkingDirectory (int): File 100% (1/1)53%  (8/15)33%  (1/3)
removeBuildResult (BuildResult): void 100% (1/1)54%  (36/67)50%  (7.1/14)
getChangesSinceLastSuccess (int, int): List 100% (1/1)55%  (55/100)48%  (16/33)
addProjectGroup (ProjectGroup): void 100% (1/1)56%  (48/85)53%  (11.2/21)
addMavenTwoProject (String, boolean): ContinuumProjectBuildingResult 100% (1/1)58%  (11/19)33%  (1/3)
removeProject (int): void 100% (1/1)60%  (140/232)67%  (33.6/50)
createProjectScmRoot (ProjectGroup, String): ProjectScmRoot 100% (1/1)62%  (24/39)67%  (6/9)
getProjectGroupByGroupId (String): ProjectGroup 100% (1/1)63%  (12/19)60%  (3/5)
activeBuildDefinitionSchedule (Schedule): void 100% (1/1)64%  (7/11)60%  (3/5)
getProjectsInBuildOrder (Collection): List 100% (1/1)69%  (9/13)67%  (2/3)
executeAddProjectsFromMetadataActivity (String, String, int, boolean, boolean... 100% (1/1)72%  (349/488)74%  (85.7/116)
isProjectInReleaseStage (Project): boolean 100% (1/1)72%  (18/25)50%  (2/4)
checkForDuplicateProjectInGroup (ProjectGroup, Project, ContinuumProjectBuild... 100% (1/1)73%  (30/41)62%  (4.9/8)
stopContinuum (): void 100% (1/1)75%  (18/24)73%  (8/11)
removeProjectGroup (int): void 100% (1/1)79%  (111/141)77%  (21.6/28)
executeAddProjectFromScmActivity (Project, int, int): int 100% (1/1)80%  (135/168)80%  (33.7/42)
addGroupNotifier (int, ProjectNotifier): ProjectNotifier 100% (1/1)88%  (49/56)88%  (14/16)
isAnyProjectsInReleaseStage (List): boolean 100% (1/1)89%  (17/19)83%  (3.3/4)
isAnyProjectInGroupInReleaseStage (int): boolean 100% (1/1)92%  (33/36)79%  (3.9/5)
getProjectScmRootByProject (int): ProjectScmRoot 100% (1/1)97%  (36/37)95%  (6.7/7)
<static initializer> 100% (1/1)100% (4/4)100% (1/1)
DefaultContinuum (): void 100% (1/1)100% (12/12)100% (4/4)
access$000 (DefaultContinuum): void 100% (1/1)100% (3/3)100% (1/1)
addBuildDefinitionToProject (int, BuildDefinition): BuildDefinition 100% (1/1)100% (23/23)100% (7/7)
addMavenTwoProject (String): ContinuumProjectBuildingResult 100% (1/1)100% (5/5)100% (1/1)
addMavenTwoProject (String, int, boolean, boolean, boolean, int): ContinuumPr... 100% (1/1)100% (10/10)100% (1/1)
addNotifier (int, ProjectNotifier): ProjectNotifier 100% (1/1)100% (47/47)100% (13/13)
addProject (Project, String, int): int 100% (1/1)100% (7/7)100% (1/1)
addProject (Project, String, int, int): int 100% (1/1)100% (9/9)100% (2/2)
closeStore (): void 100% (1/1)100% (7/7)100% (3/3)
executeAddProjectsFromMetadataActivity (String, String, int, boolean, boolean... 100% (1/1)100% (11/11)100% (1/1)
executeAddProjectsFromMetadataActivity (String, String, int, boolean, int): C... 100% (1/1)100% (10/10)100% (1/1)
getAllContinuumReleaseResults (): List 100% (1/1)100% (4/4)100% (1/1)
getAllProjectGroups (): List 100% (1/1)100% (7/7)100% (1/1)
getBuildResultsForProject (int): Collection 100% (1/1)100% (5/5)100% (1/1)
getBuildsManager (): BuildsManager 100% (1/1)100% (3/3)100% (1/1)
getConfiguration (): ConfigurationService 100% (1/1)100% (3/3)100% (1/1)
getContinuumReleaseResultsByProjectGroup (int): List 100% (1/1)100% (5/5)100% (1/1)
getInstallationService (): InstallationService 100% (1/1)100% (3/3)100% (1/1)
getProject (int): Project 100% (1/1)100% (20/20)100% (3/3)
getProjectScmRootByProjectGroup (int): List 100% (1/1)100% (5/5)100% (1/1)
getWorkingDirectory (): String 100% (1/1)100% (5/5)100% (1/1)
removeBuildDefinitionFromProject (int, int): void 100% (1/1)100% (19/19)100% (6/6)
setProjectDao (ProjectDao): void 100% (1/1)100% (4/4)100% (2/2)
setTaskQueueManager (TaskQueueManager): void 100% (1/1)100% (4/4)100% (2/2)
startMessage (): void 100% (1/1)100% (60/60)100% (14/14)
stopMessage (): void 100% (1/1)100% (9/9)100% (4/4)
updateBuildDefinitionForProjectGroup (int, BuildDefinition): BuildDefinition 100% (1/1)100% (23/23)100% (7/7)
     
class DefaultContinuum$1100% (1/1)100% (2/2)100% (10/10)100% (3/3)
DefaultContinuum$1 (DefaultContinuum): void 100% (1/1)100% (6/6)100% (1/1)
run (): void 100% (1/1)100% (4/4)100% (2/2)

1package org.apache.maven.continuum;
2 
3/*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements.  See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership.  The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License.  You may obtain a copy of the License at
11 *
12 *   http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied.  See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21 
22import org.apache.continuum.builder.distributed.manager.DistributedBuildManager;
23import org.apache.continuum.buildmanager.BuildManagerException;
24import org.apache.continuum.buildmanager.BuildsManager;
25import org.apache.continuum.buildqueue.BuildQueueService;
26import org.apache.continuum.buildqueue.BuildQueueServiceException;
27import org.apache.continuum.configuration.ContinuumConfigurationException;
28import org.apache.continuum.dao.BuildDefinitionDao;
29import org.apache.continuum.dao.BuildResultDao;
30import org.apache.continuum.dao.ContinuumReleaseResultDao;
31import org.apache.continuum.dao.DaoUtils;
32import org.apache.continuum.dao.NotifierDao;
33import org.apache.continuum.dao.ProjectDao;
34import org.apache.continuum.dao.ProjectGroupDao;
35import org.apache.continuum.dao.ProjectScmRootDao;
36import org.apache.continuum.dao.ScheduleDao;
37import org.apache.continuum.model.project.ProjectGroupSummary;
38import org.apache.continuum.model.project.ProjectScmRoot;
39import org.apache.continuum.model.release.ContinuumReleaseResult;
40import org.apache.continuum.purge.ContinuumPurgeManager;
41import org.apache.continuum.purge.PurgeConfigurationService;
42import org.apache.continuum.release.distributed.manager.DistributedReleaseManager;
43import org.apache.continuum.repository.RepositoryService;
44import org.apache.continuum.taskqueue.manager.TaskQueueManager;
45import org.apache.continuum.taskqueue.manager.TaskQueueManagerException;
46import org.apache.continuum.utils.ProjectSorter;
47import org.apache.maven.continuum.build.settings.SchedulesActivationException;
48import org.apache.maven.continuum.build.settings.SchedulesActivator;
49import org.apache.maven.continuum.builddefinition.BuildDefinitionService;
50import org.apache.maven.continuum.builddefinition.BuildDefinitionServiceException;
51import org.apache.maven.continuum.configuration.ConfigurationException;
52import org.apache.maven.continuum.configuration.ConfigurationLoadingException;
53import org.apache.maven.continuum.configuration.ConfigurationService;
54import org.apache.maven.continuum.core.action.AbstractContinuumAction;
55import org.apache.maven.continuum.core.action.CheckoutProjectContinuumAction;
56import org.apache.maven.continuum.core.action.CreateProjectsFromMetadataAction;
57import org.apache.maven.continuum.core.action.StoreProjectAction;
58import org.apache.maven.continuum.execution.ContinuumBuildExecutorConstants;
59import org.apache.maven.continuum.execution.manager.BuildExecutorManager;
60import org.apache.maven.continuum.initialization.ContinuumInitializationException;
61import org.apache.maven.continuum.initialization.ContinuumInitializer;
62import org.apache.maven.continuum.installation.InstallationService;
63import org.apache.maven.continuum.model.project.BuildDefinition;
64import org.apache.maven.continuum.model.project.BuildDefinitionTemplate;
65import org.apache.maven.continuum.model.project.BuildQueue;
66import org.apache.maven.continuum.model.project.BuildResult;
67import org.apache.maven.continuum.model.project.Project;
68import org.apache.maven.continuum.model.project.ProjectGroup;
69import org.apache.maven.continuum.model.project.ProjectNotifier;
70import org.apache.maven.continuum.model.project.Schedule;
71import org.apache.maven.continuum.model.scm.ChangeSet;
72import org.apache.maven.continuum.model.scm.ScmResult;
73import org.apache.maven.continuum.profile.ProfileService;
74import org.apache.maven.continuum.project.ContinuumProjectState;
75import org.apache.maven.continuum.project.builder.ContinuumProjectBuildingResult;
76import org.apache.maven.continuum.project.builder.maven.MavenOneContinuumProjectBuilder;
77import org.apache.maven.continuum.project.builder.maven.MavenTwoContinuumProjectBuilder;
78import org.apache.maven.continuum.release.ContinuumReleaseManager;
79import org.apache.maven.continuum.store.ContinuumObjectNotFoundException;
80import org.apache.maven.continuum.store.ContinuumStoreException;
81import org.apache.maven.continuum.utils.ContinuumUrlValidator;
82import org.apache.maven.continuum.utils.WorkingDirectoryService;
83import org.codehaus.plexus.action.Action;
84import org.codehaus.plexus.action.ActionManager;
85import org.codehaus.plexus.action.ActionNotFoundException;
86import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
87import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
88import org.codehaus.plexus.personality.plexus.lifecycle.phase.Startable;
89import org.codehaus.plexus.personality.plexus.lifecycle.phase.StartingException;
90import org.codehaus.plexus.personality.plexus.lifecycle.phase.StoppingException;
91import org.codehaus.plexus.util.FileUtils;
92import org.codehaus.plexus.util.IOUtil;
93import org.codehaus.plexus.util.StringUtils;
94import org.slf4j.Logger;
95import org.slf4j.LoggerFactory;
96import org.springframework.beans.BeanUtils;
97 
98import java.io.File;
99import java.io.IOException;
100import java.io.InputStream;
101import java.util.ArrayList;
102import java.util.Collection;
103import java.util.Collections;
104import java.util.HashMap;
105import java.util.Iterator;
106import java.util.List;
107import java.util.Map;
108import java.util.Properties;
109import java.util.regex.Matcher;
110import java.util.regex.Pattern;
111 
112/**
113 * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
114 * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l </a>
115 * @version $Id: DefaultContinuum.java 918334 2010-03-03 06:29:26Z brett $
116 * @plexus.component role="org.apache.maven.continuum.Continuum" role-hint="default"
117 */
118public class DefaultContinuum
119    implements Continuum, Initializable, Startable
120{
121    private static final Logger log = LoggerFactory.getLogger( DefaultContinuum.class );
122 
123    /**
124     * @plexus.requirement
125     */
126    private ActionManager actionManager;
127 
128    /**
129     * @plexus.requirement
130     */
131    private ConfigurationService configurationService;
132 
133    /**
134     * @plexus.requirement
135     */
136    private DaoUtils daoUtils;
137 
138    /**
139     * @plexus.requirement
140     */
141    private BuildDefinitionDao buildDefinitionDao;
142 
143    /**
144     * @plexus.requirement
145     */
146    private BuildResultDao buildResultDao;
147 
148    /**
149     * @plexus.requirement
150     */
151    private NotifierDao notifierDao;
152 
153    /**
154     * @plexus.requirement
155     */
156    private ProjectDao projectDao;
157 
158    /**
159     * @plexus.requirement
160     */
161    private ProjectGroupDao projectGroupDao;
162 
163    /**
164     * @plexus.requirement
165     */
166    private ScheduleDao scheduleDao;
167 
168    /**
169     * @plexus.requirement
170     */
171    private ContinuumReleaseResultDao releaseResultDao;
172 
173    /**
174     * @plexus.requirement
175     */
176    private ProjectScmRootDao projectScmRootDao;
177 
178    /**
179     * @plexus.requirement
180     */
181    private ContinuumInitializer initializer;
182 
183    /**
184     * @plexus.requirement
185     */
186    private SchedulesActivator schedulesActivator;
187 
188    /**
189     * @plexus.requirement
190     */
191    private InstallationService installationService;
192 
193    /**
194     * @plexus.requirement
195     */
196    private ProfileService profileService;
197 
198    /**
199     * @plexus.requirement
200     */
201    private BuildDefinitionService buildDefinitionService;
202 
203    // ----------------------------------------------------------------------
204    // Moved from core
205    // ----------------------------------------------------------------------
206 
207    /**
208     * @plexus.requirement
209     */
210    private ContinuumReleaseManager releaseManager;
211 
212    /**
213     * @plexus.requirement
214     */
215    private WorkingDirectoryService workingDirectoryService;
216 
217    /**
218     * @plexus.requirement
219     */
220    private BuildExecutorManager executorManager;
221 
222    /**
223     * @plexus.requirement role-hint="continuumUrl"
224     */
225    private ContinuumUrlValidator urlValidator;
226 
227    private boolean stopped = false;
228 
229    /**
230     * @plexus.requirement
231     */
232    private ContinuumPurgeManager purgeManager;
233 
234    /**
235     * @plexus.requirement
236     */
237    private RepositoryService repositoryService;
238 
239    /**
240     * @plexus.requirement
241     */
242    private PurgeConfigurationService purgeConfigurationService;
243 
244    /**
245     * @plexus.requirement
246     */
247    private TaskQueueManager taskQueueManager;
248 
249    /**
250     * @plexus.requirement role-hint="parallel"
251     */
252    private BuildsManager parallelBuildsManager;
253 
254    /**
255     * @plexus.requirement
256     */
257    private BuildQueueService buildQueueService;
258 
259    /**
260     * @plexus.requirement
261     */
262    private DistributedBuildManager distributedBuildManager;
263 
264    /**
265     * @plexus.requirement
266     */
267    private DistributedReleaseManager distributedReleaseManager;
268 
269    public DefaultContinuum()
270    {
271        Runtime.getRuntime().addShutdownHook( new Thread()
272        {
273            @Override
274            public void run()
275            {
276                stopContinuum();
277            }
278        } );
279    }
280 
281    public ContinuumReleaseManager getReleaseManager()
282    {
283        return releaseManager;
284    }
285 
286    public ContinuumPurgeManager getPurgeManager()
287    {
288        return purgeManager;
289    }
290 
291    public RepositoryService getRepositoryService()
292    {
293        return repositoryService;
294    }
295 
296    public TaskQueueManager getTaskQueueManager()
297    {
298        return taskQueueManager;
299    }
300 
301    public PurgeConfigurationService getPurgeConfigurationService()
302    {
303        return purgeConfigurationService;
304    }
305 
306    public BuildsManager getBuildsManager()
307    {
308        return parallelBuildsManager;
309    }
310 
311    public DistributedReleaseManager getDistributedReleaseManager()
312    {
313        return distributedReleaseManager;
314    }
315 
316    // ----------------------------------------------------------------------
317    // Project Groups
318    // ----------------------------------------------------------------------
319    public ProjectGroup getProjectGroup( int projectGroupId )
320        throws ContinuumException
321    {
322        try
323        {
324            return projectGroupDao.getProjectGroup( projectGroupId );
325        }
326        catch ( ContinuumObjectNotFoundException e )
327        {
328            throw new ContinuumException( "invalid group id", e );
329        }
330        catch ( ContinuumStoreException e )
331        {
332            throw new ContinuumException( "Error while querying for project group.", e );
333        }
334    }
335 
336    public ProjectGroup getProjectGroupWithProjects( int projectGroupId )
337        throws ContinuumException
338    {
339        try
340        {
341            return projectGroupDao.getProjectGroupWithProjects( projectGroupId );
342        }
343        catch ( ContinuumStoreException e )
344        {
345            throw new ContinuumException( "could not find project group containing " + projectGroupId );
346        }
347    }
348 
349    public ProjectGroup getProjectGroupByProjectId( int projectId )
350        throws ContinuumException
351    {
352        try
353        {
354            return projectGroupDao.getProjectGroupByProjectId( projectId );
355        }
356        catch ( ContinuumObjectNotFoundException e )
357        {
358            throw new ContinuumException( "could not find project group containing " + projectId );
359        }
360    }
361 
362    public void removeProjectGroup( int projectGroupId )
363        throws ContinuumException
364    {
365        ProjectGroup projectGroup = getProjectGroupWithProjects( projectGroupId );
366 
367        if ( projectGroup != null )
368        {
369            List<Project> projects = projectGroup.getProjects();
370            int[] projectIds = new int[projects.size()];
371 
372            int idx = 0;
373            for ( Project project : projects )
374            {
375                projectIds[idx] = project.getId();
376                idx++;
377            }
378 
379            // check if any project is still being checked out
380            // canceling the checkout and proceeding with the delete results to a cannot delete directory error!
381            try
382            {
383                if ( parallelBuildsManager.isAnyProjectCurrentlyBeingCheckedOut( projectIds ) )
384                {
385                    throw new ContinuumException(
386                        "Unable to delete group. At least one project in group is still being checked out." );
387                }
388 
389                if ( parallelBuildsManager.isAnyProjectCurrentlyBuilding( projectIds ) )
390                {
391                    throw new ContinuumException(
392                        "Unable to delete group. At least one project in group is still building." );
393                }
394 
395                if ( isAnyProjectsInReleaseStage( projects ) )
396                {
397                    throw new ContinuumException(
398                        "Unable to delete group. At least one project in group is in release stage" );
399                }
400            }
401            catch ( BuildManagerException e )
402            {
403                throw new ContinuumException( "Unable to delete group.", e );
404            }
405 
406            for ( int projectId : projectIds )
407            {
408                removeProject( projectId );
409            }
410 
411            // check if there are any project scm root left
412            List<ProjectScmRoot> scmRoots = getProjectScmRootByProjectGroup( projectGroupId );
413 
414            for ( ProjectScmRoot scmRoot : scmRoots )
415            {
416                removeProjectScmRoot( scmRoot );
417            }
418 
419            log.info( "Remove project group " + projectGroup.getName() + "(" + projectGroup.getId() + ")" );
420 
421            Map<String, Object> context = new HashMap<String, Object>();
422            AbstractContinuumAction.setProjectGroupId( context, projectGroup.getId() );
423            executeAction( "remove-assignable-roles", context );
424 
425            projectGroupDao.removeProjectGroup( projectGroup );
426        }
427    }
428 
429    public void addProjectGroup( ProjectGroup projectGroup )
430        throws ContinuumException
431    {
432        ProjectGroup pg = null;
433 
434        try
435        {
436            pg = projectGroupDao.getProjectGroupByGroupId( projectGroup.getGroupId() );
437        }
438        catch ( ContinuumObjectNotFoundException e )
439        {
440            //since we want to add a new project group, we should be getting
441            //this exception
442        }
443        catch ( ContinuumStoreException e )
444        {
445            throw new ContinuumException( "Unable to add the requested project group", e );
446        }
447 
448        if ( pg == null )
449        {
450            //CONTINUUM-1502
451            projectGroup.setName( projectGroup.getName().trim() );
452            try
453            {
454                ProjectGroup new_pg = projectGroupDao.addProjectGroup( projectGroup );
455 
456                buildDefinitionService.addBuildDefinitionTemplateToProjectGroup( new_pg.getId(),
457                                                                                 buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate() );
458 
459                Map<String, Object> context = new HashMap<String, Object>();
460                AbstractContinuumAction.setProjectGroupId( context, new_pg.getId() );
461                executeAction( "add-assignable-roles", context );
462 
463                log.info( "Added new project group: " + new_pg.getName() );
464            }
465            catch ( BuildDefinitionServiceException e )
466            {
467                throw new ContinuumException( e.getMessage(), e );
468            }
469            catch ( ContinuumObjectNotFoundException e )
470            {
471                throw new ContinuumException( e.getMessage(), e );
472            }
473 
474        }
475        else
476        {
477            throw new ContinuumException( "Unable to add the requested project group: groupId already exists." );
478        }
479 
480    }
481 
482    public List<ProjectGroup> getAllProjectGroups()
483    {
484        return new ArrayList<ProjectGroup>( projectGroupDao.getAllProjectGroups() );
485    }
486 
487    public ProjectGroup getProjectGroupByGroupId( String groupId )
488        throws ContinuumException
489    {
490        try
491        {
492            return projectGroupDao.getProjectGroupByGroupId( groupId );
493        }
494        catch ( ContinuumObjectNotFoundException e )
495        {
496            throw new ContinuumException( "Unable to find project group", e );
497        }
498        catch ( ContinuumStoreException e )
499        {
500            throw new ContinuumException( "Error retrieving", e );
501        }
502    }
503 
504    public ProjectGroup getProjectGroupByGroupIdWithBuildDetails( String groupId )
505        throws ContinuumException
506    {
507        try
508        {
509            return projectGroupDao.getProjectGroupByGroupIdWithBuildDetails( groupId );
510        }
511        catch ( ContinuumObjectNotFoundException e )
512        {
513            throw new ContinuumException( "Unable to find project group", e );
514        }
515        catch ( ContinuumStoreException e )
516        {
517            throw new ContinuumException( "Error retrieving", e );
518        }
519    }
520 
521    public List<ProjectGroup> getAllProjectGroupsWithRepository( int repositoryId )
522    {
523        return projectGroupDao.getProjectGroupByRepository( repositoryId );
524    }
525 
526    // ----------------------------------------------------------------------
527    // Projects
528    // ----------------------------------------------------------------------
529 
530    /**
531     * TODO: Remove this method
532     */
533    public Collection<Project> getProjects()
534        throws ContinuumException
535    {
536        return projectDao.getAllProjectsByName();
537    }
538 
539    /**
540     * TODO: Remove this method
541     */
542    public Collection<Project> getProjectsWithDependencies()
543        throws ContinuumException
544    {
545        return projectDao.getAllProjectsByNameWithDependencies();
546    }
547 
548    public Map<Integer, BuildResult> getLatestBuildResults( int projectGroupId )
549    {
550        Map<Integer, BuildResult> result = buildResultDao.getLatestBuildResultsByProjectGroupId( projectGroupId );
551 
552        if ( result == null )
553        {
554            result = new HashMap<Integer, BuildResult>();
555        }
556 
557        return result;
558    }
559 
560    public Map<Integer, BuildResult> getBuildResultsInSuccess( int projectGroupId )
561    {
562        Map<Integer, BuildResult> result = buildResultDao.getBuildResultsInSuccessByProjectGroupId( projectGroupId );
563 
564        if ( result == null )
565        {
566            result = new HashMap<Integer, BuildResult>();
567        }
568 
569        return result;
570    }
571 
572    public BuildResult getLatestBuildResultForProject( int projectId )
573    {
574        return buildResultDao.getLatestBuildResultForProject( projectId );
575    }
576 
577    public BuildResult getBuildResultByBuildNumber( int projectId, int buildNumber )
578        throws ContinuumException
579    {
580        List<BuildResult> builds = buildResultDao.getBuildResultByBuildNumber( projectId, buildNumber );
581 
582        return ( builds.isEmpty() ? null : builds.get( 0 ) );
583    }
584 
585    // ----------------------------------------------------------------------
586    //
587    // ----------------------------------------------------------------------
588 
589    public void removeProject( int projectId )
590        throws ContinuumException
591    {
592        try
593        {
594            Project project = getProject( projectId );
595 
596            try
597            {
598                if ( parallelBuildsManager.isProjectCurrentlyBeingCheckedOut( projectId ) )
599                {
600                    throw new ContinuumException(
601                        "Unable to remove project " + projectId + " because it is currently being checked out" );
602                }
603 
604                if ( parallelBuildsManager.isProjectInAnyCurrentBuild( projectId ) )
605                {
606                    throw new ContinuumException(
607                        "Unable to remove project " + projectId + " because it is currently building" );
608                }
609            }
610            catch ( BuildManagerException e )
611            {
612                throw new ContinuumException( e.getMessage(), e );
613            }
614 
615            if ( isProjectInReleaseStage( project ) )
616            {
617                throw new ContinuumException(
618                    "Unable to remove project " + projectId + " because it is in release stage" );
619            }
620 
621            try
622            {
623                parallelBuildsManager.removeProjectFromCheckoutQueue( projectId );
624 
625                parallelBuildsManager.removeProjectFromBuildQueue( projectId );
626            }
627            catch ( BuildManagerException e )
628            {
629                throw new ContinuumException( e.getMessage(), e );
630            }
631 
632            List<ContinuumReleaseResult> releaseResults =
633                releaseResultDao.getContinuumReleaseResultsByProject( projectId );
634 
635            ProjectScmRoot scmRoot = getProjectScmRootByProject( projectId );
636 
637            try
638            {
639                for ( ContinuumReleaseResult releaseResult : releaseResults )
640                {
641                    releaseResultDao.removeContinuumReleaseResult( releaseResult );
642                }
643 
644                File releaseOutputDirectory =
645                    configurationService.getReleaseOutputDirectory( project.getProjectGroup().getId() );
646 
647                if ( releaseOutputDirectory != null )
648                {
649                    FileUtils.deleteDirectory( releaseOutputDirectory );
650                }
651            }
652            catch ( ContinuumStoreException e )
653            {
654                throw new ContinuumException( "Error while deleting continuum release result of project group", e );
655            }
656            catch ( IOException e )
657            {
658                throw logAndCreateException( "Error while deleting project group release output directory.", e );
659            }
660 
661            log.info( "Remove project " + project.getName() + "(" + projectId + ")" );
662 
663            // remove dependencies first to avoid key clash with build results
664            project = projectDao.getProjectWithDependencies( projectId );
665            project.setParent( null );
666            project.getDependencies().clear();
667            projectDao.updateProject( project );
668 
669            Collection<BuildResult> buildResults = getBuildResultsForProject( projectId );
670 
671            for ( BuildResult br : buildResults )
672            {
673                br.setBuildDefinition( null );
674                //Remove all modified dependencies to prevent SQL errors
675                br.getModifiedDependencies().clear();
676                buildResultDao.updateBuildResult( br );
677                removeBuildResult( br );
678            }
679 
680            File workingDirectory = getWorkingDirectory( projectId );
681 
682            FileUtils.deleteDirectory( workingDirectory );
683 
684            File buildOutputDirectory = configurationService.getBuildOutputDirectory( projectId );
685 
686            FileUtils.deleteDirectory( buildOutputDirectory );
687 
688            projectDao.removeProject( projectDao.getProject( projectId ) );
689 
690            removeProjectScmRoot( scmRoot );
691        }
692        catch ( ContinuumStoreException ex )
693        {
694            throw logAndCreateException( "Error while removing project in database.", ex );
695        }
696        catch ( IOException e )
697        {
698            throw logAndCreateException( "Error while deleting project working directory.", e );
699        }
700    }
701 
702    /**
703     * @see org.apache.maven.continuum.Continuum#checkoutProject(int)
704     */
705    public void checkoutProject( int projectId )
706        throws ContinuumException
707    {
708        Map<String, Object> context = new HashMap<String, Object>();
709 
710        AbstractContinuumAction.setProjectId( context, projectId );
711 
712        try
713        {
714            BuildDefinition buildDefinition = buildDefinitionDao.getDefaultBuildDefinition( projectId );
715            AbstractContinuumAction.setBuildDefinition( context, buildDefinition );
716 
717            executeAction( "add-project-to-checkout-queue", context );
718        }
719        catch ( ContinuumStoreException e )
720        {
721            throw new ContinuumException( e.getMessage(), e );
722        }
723    }
724 
725    public Project getProject( int projectId )
726        throws ContinuumException
727    {
728        try
729        {
730            return projectDao.getProject( projectId );
731        }
732        catch ( ContinuumStoreException ex )
733        {
734            throw logAndCreateException( "Exception while getting project '" + projectId + "'.", ex );
735        }
736    }
737 
738    public Project getProjectWithBuildDetails( int projectId )
739        throws ContinuumException
740    {
741        try
742        {
743            return projectDao.getProjectWithBuildDetails( projectId );
744        }
745        catch ( ContinuumStoreException ex )
746        {
747            throw logAndCreateException( "Exception while getting project '" + projectId + "'.", ex );
748        }
749    }
750 
751    public Map<Integer, ProjectGroupSummary> getProjectsSummaryByGroups()
752    {
753        return projectDao.getProjectsSummary();
754    }
755 
756    // ----------------------------------------------------------------------
757    // Building
758    // ----------------------------------------------------------------------
759 
760    /**
761     * TODO: Remove this method
762     */
763    public void buildProjects()
764        throws ContinuumException
765    {
766        buildProjects( ContinuumProjectState.TRIGGER_FORCED );
767    }
768 
769    public void buildProjectsWithBuildDefinition( List<Project> projects, List<BuildDefinition> bds )
770        throws ContinuumException
771    {
772        Collection<Project> filteredProjectsList = getProjectsNotInReleaseStage( projects );
773 
774        prepareBuildProjects( filteredProjectsList, bds, true, ContinuumProjectState.TRIGGER_FORCED );
775    }
776 
777    public void buildProjectsWithBuildDefinition( List<Project> projects, int buildDefinitionId )
778        throws ContinuumException
779    {
780        Collection<Project> filteredProjectsList = getProjectsNotInReleaseStage( projects );
781 
782        prepareBuildProjects( filteredProjectsList, buildDefinitionId, ContinuumProjectState.TRIGGER_FORCED );
783    }
784 
785    /**
786     * fire of the builds of all projects across all project groups using their default build definitions
787     * TODO:Remove this method
788     *
789     * @param trigger
790     * @throws ContinuumException
791     */
792    public void buildProjects( int trigger )
793        throws ContinuumException
794    {
795        Collection<Project> projectsList = getProjectsInBuildOrder();
796 
797        Collection<Project> filteredProjectsList = getProjectsNotInReleaseStage( projectsList );
798 
799        prepareBuildProjects( filteredProjectsList, null, true, trigger );
800    }
801 
802    /**
803     * fire off a build for all of the projects in a project group using their default builds
804     *
805     * @param projectGroupId
806     * @throws ContinuumException
807     */
808    public void buildProjectGroup( int projectGroupId )
809        throws ContinuumException
810    {
811        List<BuildDefinition> groupDefaultBDs;
812 
813        if ( !isAnyProjectInGroupInReleaseStage( projectGroupId ) )
814        {
815            groupDefaultBDs = getDefaultBuildDefinitionsForProjectGroup( projectGroupId );
816 
817            buildProjectGroupWithBuildDefinition( projectGroupId, groupDefaultBDs, true );
818        }
819    }
820 
821    /**
822     * fire off a build for all of the projects in a project group using their default builds.
823     *
824     * @param projectGroupId    the project group id
825     * @param buildDefinitionId the build definition id to use
826     * @throws ContinuumException
827     */
828    public void buildProjectGroupWithBuildDefinition( int projectGroupId, int buildDefinitionId )
829        throws ContinuumException
830    {
831        if ( !isAnyProjectInGroupInReleaseStage( projectGroupId ) )
832        {
833            List<BuildDefinition> bds = new ArrayList<BuildDefinition>();
834            BuildDefinition bd = getBuildDefinition( buildDefinitionId );
835            if ( bd != null )
836            {
837                bds.add( bd );
838            }
839            buildProjectGroupWithBuildDefinition( projectGroupId, bds, false );
840        }
841    }
842 
843    /**
844     * fire off a build for all of the projects in a project group using their default builds
845     *
846     * @param projectGroupId
847     * @throws ContinuumException
848     */
849    private void buildProjectGroupWithBuildDefinition( int projectGroupId, List<BuildDefinition> bds,
850                                                       boolean checkDefaultBuildDefinitionForProject )
851        throws ContinuumException
852    {
853        if ( !isAnyProjectInGroupInReleaseStage( projectGroupId ) )
854        {
855            Collection<Project> projectsList;
856 
857            projectsList = getProjectsInBuildOrder( projectDao.getProjectsWithDependenciesByGroupId( projectGroupId ) );
858 
859            prepareBuildProjects( projectsList, bds, checkDefaultBuildDefinitionForProject,
860                                  ContinuumProjectState.TRIGGER_FORCED );
861        }
862    }
863 
864    /**
865     * takes a given schedule and determines which projects need to build
866     * <p/>
867     * The build order is determined by the dependencies
868     *
869     * @param schedule The schedule
870     * @throws ContinuumException
871     */
872    public void buildProjects( Schedule schedule )
873        throws ContinuumException
874    {
875        Collection<Project> projectsList;
876 
877        Map<Integer, Object> projectsMap;
878 
879        try
880        {
881            projectsMap = daoUtils.getAggregatedProjectIdsAndBuildDefinitionIdsBySchedule( schedule.getId() );
882 
883            if ( projectsMap == null || projectsMap.size() == 0 )
884            {
885                log.debug( "no builds attached to schedule" );
886                try
887                {
888                    schedulesActivator.unactivateOrphanBuildSchedule( schedule );
889                }
890                catch ( SchedulesActivationException e )
891                {
892                    log.debug( "Can't unactivate orphan shcedule for buildDefinitions" );
893                }
894                // We don't have projects attached to this schedule. This is because it's only is setting for a
895                // templateBuildDefinition
896                return;
897            }
898 
899            //TODO: As all projects are built in the same queue for a project group, it would be better to get them by
900            // project group and add them in queues in parallel to save few seconds
901            projectsList = getProjectsInBuildOrder();
902        }
903        catch ( ContinuumStoreException e )
904        {
905            throw new ContinuumException( "Can't get project list for schedule " + schedule.getName(), e );
906        }
907 
908        Map<ProjectScmRoot, Map<Integer, Integer>> map = new HashMap<ProjectScmRoot, Map<Integer, Integer>>();
909        List<ProjectScmRoot> sortedScmRoot = new ArrayList<ProjectScmRoot>();
910 
911        for ( Project project : projectsList )
912        {
913            List<Integer> buildDefIds = (List<Integer>) projectsMap.get( project.getId() );
914 
915            if ( buildDefIds != null && !buildDefIds.isEmpty() )
916            {
917                for ( Integer buildDefId : buildDefIds )
918                {
919                    try
920                    {
921                        if ( buildDefId != null &&
922                            !parallelBuildsManager.isInAnyBuildQueue( project.getId(), buildDefId ) &&
923                            !parallelBuildsManager.isInAnyCheckoutQueue( project.getId() ) &&
924                            !parallelBuildsManager.isInPrepareBuildQueue( project.getId() ) &&
925                            !parallelBuildsManager.isProjectCurrentlyPreparingBuild( project.getId() ) )
926                        {
927                            ProjectScmRoot scmRoot = getProjectScmRootByProject( project.getId() );
928 
929                            Map<Integer, Integer> projectsAndBuildDefinitionsMap = map.get( scmRoot );
930 
931                            if ( projectsAndBuildDefinitionsMap == null )
932                            {
933                                projectsAndBuildDefinitionsMap = new HashMap<Integer, Integer>();
934                            }
935 
936                            projectsAndBuildDefinitionsMap.put( project.getId(), buildDefId );
937 
938                            map.put( scmRoot, projectsAndBuildDefinitionsMap );
939 
940                            if ( !sortedScmRoot.contains( scmRoot ) )
941                            {
942                                sortedScmRoot.add( scmRoot );
943                            }
944                        }
945                    }
946                    catch ( BuildManagerException e )
947                    {
948                        throw new ContinuumException( e.getMessage(), e );
949                    }
950                }
951            }
952        }
953 
954        prepareBuildProjects( map, ContinuumProjectState.TRIGGER_SCHEDULED, sortedScmRoot );
955    }
956 
957    public void buildProject( int projectId )
958        throws ContinuumException
959    {
960        buildProject( projectId, ContinuumProjectState.TRIGGER_FORCED );
961    }
962 
963    public void buildProjectWithBuildDefinition( int projectId, int buildDefinitionId )
964        throws ContinuumException
965    {
966        buildProject( projectId, buildDefinitionId, ContinuumProjectState.TRIGGER_FORCED );
967    }
968 
969    public void buildProject( int projectId, int trigger )
970        throws ContinuumException
971    {
972        Project project = getProject( projectId );
973        if ( isProjectInReleaseStage( project ) )
974        {
975            throw new ContinuumException( "Project (id=" + projectId + ") is currently in release stage." );
976        }
977 
978        BuildDefinition buildDef = getDefaultBuildDefinition( projectId );
979 
980        if ( buildDef == null )
981        {
982            throw new ContinuumException( "Project (id=" + projectId + " doens't have a default build definition." );
983        }
984 
985        try
986        {
987            if ( parallelBuildsManager.isInAnyBuildQueue( projectId, buildDef.getId() ) ||
988                parallelBuildsManager.isInAnyCheckoutQueue( projectId ) ||
989                parallelBuildsManager.isInPrepareBuildQueue( projectId ) )
990            {
991                return;
992            }
993        }
994        catch ( BuildManagerException e )
995        {
996            throw new ContinuumException( e.getMessage(), e );
997        }
998 
999        Map<Integer, Integer> projectsBuildDefinitionsMap = new HashMap<Integer, Integer>();
1000        projectsBuildDefinitionsMap.put( projectId, buildDef.getId() );
1001 
1002        ProjectScmRoot scmRoot = getProjectScmRootByProject( projectId );
1003        prepareBuildProjects( projectsBuildDefinitionsMap, trigger, scmRoot.getScmRootAddress(),
1004                              scmRoot.getProjectGroup().getId(), scmRoot.getId() );
1005    }
1006 
1007    public void buildProject( int projectId, int buildDefinitionId, int trigger )
1008        throws ContinuumException
1009    {
1010        Project project = getProject( projectId );
1011        if ( isProjectInReleaseStage( project ) )
1012        {
1013            throw new ContinuumException( "Project (id=" + projectId + ") is currently in release stage." );
1014        }
1015 
1016        try
1017        {
1018            if ( parallelBuildsManager.isInAnyBuildQueue( projectId, buildDefinitionId ) ||
1019                parallelBuildsManager.isInAnyCheckoutQueue( projectId ) ||
1020                parallelBuildsManager.isInPrepareBuildQueue( projectId ) )
1021            {
1022                return;
1023            }
1024        }
1025        catch ( BuildManagerException e )
1026        {
1027            throw new ContinuumException( e.getMessage(), e );
1028        }
1029 
1030        Map<Integer, Integer> projectsBuildDefinitionsMap = new HashMap<Integer, Integer>();
1031        projectsBuildDefinitionsMap.put( projectId, buildDefinitionId );
1032 
1033        ProjectScmRoot scmRoot = getProjectScmRootByProject( projectId );
1034        prepareBuildProjects( projectsBuildDefinitionsMap, trigger, scmRoot.getScmRootAddress(),
1035                              scmRoot.getProjectGroup().getId(), scmRoot.getId() );
1036    }
1037 
1038    public BuildResult getBuildResult( int buildId )
1039        throws ContinuumException
1040    {
1041        try
1042        {
1043            return buildResultDao.getBuildResult( buildId );
1044        }
1045        catch ( ContinuumStoreException e )
1046        {
1047            throw logAndCreateException( "Exception while getting build result for project.", e );
1048        }
1049    }
1050 
1051    public void removeBuildResult( int buildId )
1052        throws ContinuumException
1053    {
1054        BuildResult buildResult = getBuildResult( buildId );
1055 
1056        // check first if build result is currently being used by a building project
1057        Project project = buildResult.getProject();
1058        BuildResult bResult = getLatestBuildResultForProject( project.getId() );
1059 
1060        try
1061        {
1062            if ( bResult != null && buildResult.getId() == bResult.getId() &&
1063                parallelBuildsManager.isProjectInAnyCurrentBuild( project.getId() ) )
1064            {
1065                throw new ContinuumException(
1066                    "Unable to remove build result because it is currently being used by" + "a building project " +
1067                        project.getId() );
1068            }
1069        }
1070        catch ( BuildManagerException e )
1071        {
1072            throw new ContinuumException( e.getMessage(), e );
1073        }
1074 
1075        buildResult.getModifiedDependencies().clear();
1076        buildResult.setBuildDefinition( null );
1077 
1078        try
1079        {
1080            buildResultDao.updateBuildResult( buildResult );
1081        }
1082        catch ( ContinuumStoreException e )
1083        {
1084            throw logAndCreateException( "Error while removing build result in database.", e );
1085        }
1086        removeBuildResult( buildResult );
1087    }
1088 
1089 
1090    private void removeBuildResult( BuildResult buildResult )
1091    {
1092        buildResultDao.removeBuildResult( buildResult );
1093 
1094        // cleanup some files
1095        try
1096        {
1097            File buildOutputDirectory = getConfiguration().getBuildOutputDirectory( buildResult.getProject().getId() );
1098            File buildDirectory = new File( buildOutputDirectory, Integer.toString( buildResult.getId() ) );
1099 
1100            if ( buildDirectory.exists() )
1101            {
1102                FileUtils.deleteDirectory( buildDirectory );
1103            }
1104            File buildOutputFile =
1105                getConfiguration().getBuildOutputFile( buildResult.getId(), buildResult.getProject().getId() );
1106            if ( buildOutputFile.exists() )
1107            {
1108                FileUtils.forceDelete( buildOutputFile );
1109            }
1110        }
1111        catch ( ConfigurationException e )
1112        {
1113            log.info( "skip error during cleanup build files " + e.getMessage(), e );
1114        }
1115        catch ( IOException e )
1116        {
1117            log.info( "skip IOException during cleanup build files " + e.getMessage(), e );
1118        }
1119 
1120    }
1121 
1122    public String getBuildOutput( int projectId, int buildId )
1123        throws ContinuumException
1124    {
1125        try
1126        {
1127            return configurationService.getBuildOutput( buildId, projectId );
1128        }
1129        catch ( ConfigurationException e )
1130        {
1131            throw logAndCreateException( "Exception while getting build result for project.", e );
1132        }
1133    }
1134 
1135    /**
1136     * TODO: Must be done by build definition
1137     */
1138    public List<ChangeSet> getChangesSinceLastSuccess( int projectId, int buildResultId )
1139        throws ContinuumException
1140    {
1141        BuildResult previousBuildResult = null;
1142        try
1143        {
1144            previousBuildResult = buildResultDao.getPreviousBuildResultInSuccess( projectId, buildResultId );
1145        }
1146        catch ( ContinuumStoreException e )
1147        {
1148            //No previous build in success, Nothing to do
1149        }
1150        long startTime = previousBuildResult == null ? 0 : previousBuildResult.getStartTime();
1151        ArrayList<BuildResult> buildResults = new ArrayList<BuildResult>(
1152            buildResultDao.getBuildResultsForProjectWithDetails( projectId, startTime, buildResultId ) );
1153 
1154        Collections.reverse( buildResults );
1155 
1156        Iterator<BuildResult> buildResultsIterator = buildResults.iterator();
1157 
1158        boolean stop = false;
1159 
1160        //TODO: Shouldn't be used now with the previous call of buildResultDao.getBuildResultsForProjectWithDetails
1161        while ( !stop )
1162        {
1163            if ( buildResultsIterator.hasNext() )
1164            {
1165                BuildResult buildResult = buildResultsIterator.next();
1166 
1167                if ( buildResult.getId() == buildResultId )
1168                {
1169                    stop = true;
1170                }
1171            }
1172            else
1173            {
1174                stop = true;
1175            }
1176        }
1177 
1178        if ( !buildResultsIterator.hasNext() )
1179        {
1180            return null;
1181        }
1182 
1183        BuildResult buildResult = buildResultsIterator.next();
1184 
1185        List<ChangeSet> changes = null;
1186 
1187        while ( buildResult.getState() != ContinuumProjectState.OK )
1188        {
1189            if ( changes == null )
1190            {
1191                changes = new ArrayList<ChangeSet>();
1192            }
1193 
1194            ScmResult scmResult = buildResult.getScmResult();
1195 
1196            if ( scmResult != null )
1197            {
1198                changes.addAll( scmResult.getChanges() );
1199            }
1200 
1201            if ( !buildResultsIterator.hasNext() )
1202            {
1203                return changes;
1204            }
1205 
1206            buildResult = buildResultsIterator.next();
1207        }
1208 
1209        if ( changes == null )
1210        {
1211            changes = Collections.EMPTY_LIST;
1212        }
1213 
1214        return changes;
1215    }
1216 
1217    // ----------------------------------------------------------------------
1218    //
1219    // ----------------------------------------------------------------------
1220 
1221    /**
1222     * TODO: Remove this method when it won't be used
1223     */
1224    private List<Project> getProjectsInBuildOrder()
1225        throws ContinuumException
1226    {
1227        return getProjectsInBuildOrder( getProjectsWithDependencies() );
1228    }
1229 
1230    /**
1231     * take a collection of projects and sort for order
1232     *
1233     * @param projects
1234     * @return
1235     */
1236    public List<Project> getProjectsInBuildOrder( Collection<Project> projects )
1237    {
1238        if ( projects == null || projects.isEmpty() )
1239        {
1240            return new ArrayList<Project>();
1241        }
1242 
1243        return ProjectSorter.getSortedProjects( projects, log );
1244    }
1245 
1246    // ----------------------------------------------------------------------
1247    // Maven 1.x projects
1248    // ----------------------------------------------------------------------
1249 
1250    public ContinuumProjectBuildingResult addMavenOneProject( String metadataUrl, int projectGroupId )
1251        throws ContinuumException
1252    {
1253        return addMavenOneProject( metadataUrl, projectGroupId, true );
1254    }
1255 
1256    public ContinuumProjectBuildingResult addMavenOneProject( String metadataUrl, int projectGroupId,
1257                                                              boolean checkProtocol )
1258        throws ContinuumException
1259    {
1260        return addMavenOneProject( metadataUrl, projectGroupId, checkProtocol, false );
1261    }
1262 
1263    public ContinuumProjectBuildingResult addMavenOneProject( String metadataUrl, int projectGroupId,
1264                                                              boolean checkProtocol, boolean useCredentialsCache )
1265        throws ContinuumException
1266    {
1267        try
1268        {
1269            return addMavenOneProject( metadataUrl, projectGroupId, checkProtocol, useCredentialsCache,
1270                                       buildDefinitionService.getDefaultMavenOneBuildDefinitionTemplate().getId() );
1271        }
1272        catch ( BuildDefinitionServiceException e )
1273        {
1274            throw new ContinuumException( e.getMessage(), e );
1275        }
1276    }
1277 
1278    public ContinuumProjectBuildingResult addMavenOneProject( String metadataUrl, int projectGroupId,
1279                                                              boolean checkProtocol, boolean useCredentialsCache,
1280                                                              int buildDefinitionTemplateId )
1281        throws ContinuumException
1282    {
1283        return executeAddProjectsFromMetadataActivity( metadataUrl, MavenOneContinuumProjectBuilder.ID, projectGroupId,
1284                                                       checkProtocol, useCredentialsCache, true,
1285                                                       buildDefinitionTemplateId );
1286    }
1287 
1288    // ----------------------------------------------------------------------
1289    // Maven 2.x projects
1290    // ----------------------------------------------------------------------
1291 
1292    public ContinuumProjectBuildingResult addMavenTwoProject( String metadataUrl )
1293        throws ContinuumException
1294    {
1295        return addMavenTwoProject( metadataUrl, true );
1296    }
1297 
1298    public ContinuumProjectBuildingResult addMavenTwoProject( String metadataUrl, boolean checkProtocol )
1299        throws ContinuumException
1300    {
1301        try
1302        {
1303            return executeAddProjectsFromMetadataActivity( metadataUrl, MavenTwoContinuumProjectBuilder.ID, -1,
1304                                                           checkProtocol,
1305                                                           buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate().getId() );
1306        }
1307        catch ( BuildDefinitionServiceException e )
1308        {
1309            throw new ContinuumException( e.getMessage(), e );
1310        }
1311    }
1312 
1313    public ContinuumProjectBuildingResult addMavenTwoProject( String metadataUrl, int projectGroupId )
1314        throws ContinuumException
1315    {
1316        return addMavenTwoProject( metadataUrl, projectGroupId, true );
1317    }
1318 
1319    public ContinuumProjectBuildingResult addMavenTwoProject( String metadataUrl, int projectGroupId,
1320                                                              boolean checkProtocol )
1321        throws ContinuumException
1322    {
1323        return addMavenTwoProject( metadataUrl, projectGroupId, checkProtocol, false );
1324    }
1325 
1326    public ContinuumProjectBuildingResult addMavenTwoProject( String metadataUrl, int projectGroupId,
1327                                                              boolean checkProtocol, boolean useCredentialsCache )
1328        throws ContinuumException
1329    {
1330        try
1331        {
1332            return executeAddProjectsFromMetadataActivity( metadataUrl, MavenTwoContinuumProjectBuilder.ID,
1333                                                           projectGroupId, checkProtocol, useCredentialsCache, true,
1334                                                           buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate().getId() );
1335        }
1336        catch ( BuildDefinitionServiceException e )
1337        {
1338            throw new ContinuumException( e.getMessage(), e );
1339        }
1340    }
1341 
1342    public ContinuumProjectBuildingResult addMavenTwoProject( String metadataUrl, int projectGroupId,
1343                                                              boolean checkProtocol, boolean useCredentialsCache,
1344                                                              boolean recursiveProjects )
1345        throws ContinuumException
1346    {
1347        try
1348        {
1349            return executeAddProjectsFromMetadataActivity( metadataUrl, MavenTwoContinuumProjectBuilder.ID,
1350                                                           projectGroupId, checkProtocol, useCredentialsCache,
1351                                                           recursiveProjects,
1352                                                           buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate().getId() );
1353        }
1354        catch ( BuildDefinitionServiceException e )
1355        {
1356            throw new ContinuumException( e.getMessage(), e );
1357        }
1358    }
1359 
1360    public ContinuumProjectBuildingResult addMavenTwoProject( String metadataUrl, int projectGroupId,
1361                                                              boolean checkProtocol, boolean useCredentialsCache,
1362                                                              boolean recursiveProjects, int buildDefinitionTemplateId )
1363        throws ContinuumException
1364    {
1365        return executeAddProjectsFromMetadataActivity( metadataUrl, MavenTwoContinuumProjectBuilder.ID, projectGroupId,
1366                                                       checkProtocol, useCredentialsCache, recursiveProjects,
1367                                                       buildDefinitionTemplateId );
1368    }
1369 
1370    // ----------------------------------------------------------------------
1371    // Shell projects
1372    // ----------------------------------------------------------------------
1373 
1374    public int addProject( Project project, String executorId, int groupId )
1375        throws ContinuumException
1376    {
1377        return addProject( project, executorId, groupId, -1 );
1378    }
1379 
1380    /**
1381     * @see org.apache.maven.continuum.Continuum#addProject(org.apache.maven.continuum.model.project.Project, java.lang.String, int, int)
1382     */
1383    public int addProject( Project project, String executorId, int groupId, int buildDefinitionTemplateId )
1384        throws ContinuumException
1385    {
1386        project.setExecutorId( executorId );
1387 
1388        return executeAddProjectFromScmActivity( project, groupId, buildDefinitionTemplateId );
1389    }
1390 
1391    // ----------------------------------------------------------------------
1392    // Activities. These should end up as workflows in werkflow
1393    // ----------------------------------------------------------------------
1394 
1395    private int executeAddProjectFromScmActivity( Project project, int groupId, int buildDefinitionTemplateId )
1396        throws ContinuumException
1397    {
1398        String executorId = project.getExecutorId();
1399 
1400        ProjectGroup projectGroup = getProjectGroupWithBuildDetails( groupId );
1401 
1402        Map<String, Object> context = new HashMap<String, Object>();
1403 
1404        String scmUrl = project.getScmUrl();
1405 
1406        List<ProjectScmRoot> scmRoots = getProjectScmRootByProjectGroup( groupId );
1407 
1408        boolean found = false;
1409 
1410        for ( ProjectScmRoot scmRoot : scmRoots )
1411        {
1412            if ( scmUrl.startsWith( scmRoot.getScmRootAddress() ) )
1413            {
1414                found = true;
1415                break;
1416            }
1417        }
1418 
1419        if ( !found )
1420        {
1421            createProjectScmRoot( projectGroup, scmUrl );
1422        }
1423 
1424        // ----------------------------------------------------------------------
1425        //
1426        // ----------------------------------------------------------------------
1427 
1428        AbstractContinuumAction.setWorkingDirectory( context, getWorkingDirectory() );
1429 
1430        AbstractContinuumAction.setUnvalidatedProject( context, project );
1431 
1432        AbstractContinuumAction.setUnvalidatedProjectGroup( context, projectGroup );
1433 
1434        AbstractContinuumAction.setProjectGroupId( context, projectGroup.getId() );
1435        
1436        StoreProjectAction.setUseScmCredentialsCache( context, project.isScmUseCache() );
1437        
1438        // set for initial checkout
1439        String scmUsername = project.getScmUsername();
1440        String scmPassword = project.getScmPassword();
1441        
1442        if( scmUsername != null && !StringUtils.isEmpty( scmUsername ) )
1443        {
1444            CheckoutProjectContinuumAction.setScmUsername( context, scmUsername );
1445        }
1446        
1447        if( scmPassword != null && !StringUtils.isEmpty( scmPassword ) )
1448        {
1449            CheckoutProjectContinuumAction.setScmPassword( context, scmPassword );
1450        }
1451 
1452        executeAction( "validate-project", context );
1453 
1454        executeAction( "store-project", context );
1455 
1456        try
1457        {
1458            BuildDefinitionTemplate bdt;
1459 
1460            if ( executorId.equalsIgnoreCase( ContinuumBuildExecutorConstants.ANT_BUILD_EXECUTOR ) )
1461            {
1462                if ( buildDefinitionTemplateId <= 0 )
1463                {
1464                    bdt = buildDefinitionService.getDefaultAntBuildDefinitionTemplate();
1465                }
1466                else
1467                {
1468                    bdt = buildDefinitionService.getBuildDefinitionTemplate( buildDefinitionTemplateId );
1469                }
1470            }
1471            else
1472            {
1473                //shell default
1474                if ( buildDefinitionTemplateId <= 0 )
1475                {
1476                    bdt = buildDefinitionService.getDefaultShellBuildDefinitionTemplate();
1477                }
1478                else
1479                {
1480                    bdt = buildDefinitionService.getBuildDefinitionTemplate( buildDefinitionTemplateId );
1481                }
1482            }
1483 
1484            buildDefinitionService.addTemplateInProject( bdt.getId(), getProject(
1485                AbstractContinuumAction.getProjectId( context ) ) );
1486        }
1487        catch ( BuildDefinitionServiceException e )
1488        {
1489            throw new ContinuumException( e.getMessage(), e );
1490        }
1491 
1492        if ( !configurationService.isDistributedBuildEnabled() )
1493        {
1494            // used by BuildManager to determine on which build queue will the project be put
1495            BuildDefinition bd = (BuildDefinition) getProjectWithBuildDetails(
1496                AbstractContinuumAction.getProjectId( context ) ).getBuildDefinitions().get( 0 );
1497            AbstractContinuumAction.setBuildDefinition( context, bd );
1498 
1499            executeAction( "add-project-to-checkout-queue", context );
1500        }
1501 
1502        executeAction( "add-assignable-roles", context );
1503 
1504        return AbstractContinuumAction.getProjectId( context );
1505    }
1506 
1507    private ContinuumProjectBuildingResult executeAddProjectsFromMetadataActivity( String metadataUrl,
1508                                                                                   String projectBuilderId,
1509                                                                                   int projectGroupId,
1510                                                                                   boolean checkProtocol,
1511                                                                                   int buildDefinitionTemplateId )
1512        throws ContinuumException
1513    {
1514        return executeAddProjectsFromMetadataActivity( metadataUrl, projectBuilderId, projectGroupId, checkProtocol,
1515                                                       false, false, buildDefinitionTemplateId );
1516    }
1517 
1518 
1519    protected ContinuumProjectBuildingResult executeAddProjectsFromMetadataActivity( String metadataUrl,
1520                                                                                     String projectBuilderId,
1521                                                                                     int projectGroupId,
1522                                                                                     boolean checkProtocol,
1523                                                                                     boolean useCredentialsCache,
1524                                                                                     boolean loadRecursiveProjects,
1525                                                                                     int buildDefinitionTemplateId,
1526                                                                                     boolean addAssignableRoles )
1527        throws ContinuumException
1528    {
1529        if ( checkProtocol )
1530        {
1531            if ( !urlValidator.validate( metadataUrl ) )
1532            {
1533                ContinuumProjectBuildingResult res = new ContinuumProjectBuildingResult();
1534                res.addError( ContinuumProjectBuildingResult.ERROR_PROTOCOL_NOT_ALLOWED );
1535                return res;
1536            }
1537        }
1538 
1539        Map<String, Object> context = new HashMap<String, Object>();
1540 
1541        CreateProjectsFromMetadataAction.setProjectBuilderId( context, projectBuilderId );
1542 
1543        CreateProjectsFromMetadataAction.setUrl( context, metadataUrl );
1544 
1545        CreateProjectsFromMetadataAction.setLoadRecursiveProject( context, loadRecursiveProjects );
1546 
1547        StoreProjectAction.setUseScmCredentialsCache( context, useCredentialsCache );
1548 
1549        AbstractContinuumAction.setWorkingDirectory( context, getWorkingDirectory() );
1550 
1551        // CreateProjectsFromMetadataAction will check null and use default
1552        if ( buildDefinitionTemplateId > 0 )
1553        {
1554            try
1555            {
1556                AbstractContinuumAction.setBuildDefinitionTemplate( context,
1557                                                                    buildDefinitionService.getBuildDefinitionTemplate(
1558                                                                        buildDefinitionTemplateId ) );
1559            }
1560            catch ( BuildDefinitionServiceException e )
1561            {
1562                throw new ContinuumException( e.getMessage(), e );
1563            }
1564        }
1565        // ----------------------------------------------------------------------
1566        // Create the projects from the URL
1567        // ----------------------------------------------------------------------
1568 
1569        executeAction( "create-projects-from-metadata", context );
1570 
1571        ContinuumProjectBuildingResult result = CreateProjectsFromMetadataAction.getProjectBuildingResult( context );
1572 
1573        if ( log.isInfoEnabled() )
1574        {
1575            if ( result.getProjects() != null )
1576            {
1577                log.info( "Created " + result.getProjects().size() + " projects." );
1578            }
1579            if ( result.getProjectGroups() != null )
1580            {
1581                log.info( "Created " + result.getProjectGroups().size() + " project groups." );
1582            }
1583            log.info( result.getErrors().size() + " errors." );
1584 
1585            // ----------------------------------------------------------------------
1586            // Look for any errors.
1587            // ----------------------------------------------------------------------
1588 
1589            if ( result.hasErrors() )
1590            {
1591                log.info( result.getErrors().size() + " errors during project add: " );
1592                log.info( result.getErrorsAsString() );
1593                return result;
1594            }
1595        }
1596 
1597        // ----------------------------------------------------------------------
1598        // Save any new project groups that we've found. Currently all projects
1599        // will go into the first project group in the list.
1600        // ----------------------------------------------------------------------
1601 
1602        if ( result.getProjectGroups().size() != 1 )
1603        {
1604            throw new ContinuumException( "The project building result has to contain exactly one project group." );
1605        }
1606 
1607        ProjectGroup projectGroup = result.getProjectGroups().iterator().next();
1608 
1609        boolean projectGroupCreation = false;
1610 
1611        try
1612        {
1613            if ( projectGroupId == -1 )
1614            {
1615                try
1616                {
1617                    projectGroup = projectGroupDao.getProjectGroupByGroupId( projectGroup.getGroupId() );
1618 
1619                    projectGroupId = projectGroup.getId();
1620 
1621                    log.info( "Using existing project group with the group id: '" + projectGroup.getGroupId() + "'." );
1622                }
1623                catch ( ContinuumObjectNotFoundException e )
1624                {
1625                    log.info( "Creating project group with the group id: '" + projectGroup.getGroupId() + "'." );
1626 
1627                    Map<String, Object> pgContext = new HashMap<String, Object>();
1628 
1629                    AbstractContinuumAction.setWorkingDirectory( pgContext, getWorkingDirectory() );
1630 
1631                    AbstractContinuumAction.setUnvalidatedProjectGroup( pgContext, projectGroup );
1632 
1633                    executeAction( "validate-project-group", pgContext );
1634 
1635                    executeAction( "store-project-group", pgContext );
1636 
1637                    projectGroupId = AbstractContinuumAction.getProjectGroupId( pgContext );
1638 
1639                    projectGroupCreation = true;
1640                }
1641            }
1642 
1643            projectGroup = projectGroupDao.getProjectGroupWithBuildDetailsByProjectGroupId( projectGroupId );
1644 
1645            String url = CreateProjectsFromMetadataAction.getUrl( context );
1646 
1647            List<ProjectScmRoot> scmRoots = getProjectScmRootByProjectGroup( projectGroup.getId() );
1648 
1649            boolean found = false;
1650 
1651            for ( ProjectScmRoot scmRoot : scmRoots )
1652            {
1653                if ( url.startsWith( scmRoot.getScmRootAddress() ) )
1654                {
1655                    found = true;
1656                    break;
1657                }
1658            }
1659 
1660            if ( !found )
1661            {
1662                createProjectScmRoot( projectGroup, url );
1663            }
1664 
1665            /* add the project group loaded from database, which has more info, like id */
1666            result.getProjectGroups().remove( 0 );
1667            result.getProjectGroups().add( projectGroup );
1668        }
1669        catch ( ContinuumStoreException e )
1670        {
1671            throw new ContinuumException( "Error while querying for project group.", e );
1672        }
1673 
1674        // ----------------------------------------------------------------------
1675        // Save all the projects if recursive mode asked
1676        // TODO: Validate all the projects before saving them
1677        // ----------------------------------------------------------------------
1678 
1679        List<Project> projects = result.getProjects();
1680 
1681        String scmUserName = null;
1682        String scmPassword = null;
1683 
1684        for ( Project project : projects )
1685        {
1686            checkForDuplicateProjectInGroup( projectGroup, project, result );
1687 
1688            if ( result.hasErrors() )
1689            {
1690                log.info( result.getErrors().size() + " errors during project add: " );
1691                log.info( result.getErrorsAsString() );
1692                return result;
1693            }
1694 
1695            project.setScmUseCache( useCredentialsCache );
1696 
1697            // values backup for first checkout
1698            scmUserName = project.getScmUsername();
1699            scmPassword = project.getScmPassword();
1700            // CONTINUUM-1792 : we don't store it
1701            if ( useCredentialsCache )
1702            {
1703                project.setScmUsername( null );
1704                project.setScmPassword( null );
1705            }
1706 
1707            projectGroup.addProject( project );
1708        }
1709 
1710        try
1711        {
1712            projectGroupDao.updateProjectGroup( projectGroup );
1713 
1714            for ( Project project : projects )
1715            {
1716                context = new HashMap<String, Object>();
1717 
1718                // CONTINUUM-1953 olamy : attached buildDefs from template here
1719                // if no group creation
1720                if ( !projectGroupCreation && buildDefinitionTemplateId > 0 )
1721                {
1722                    buildDefinitionService.addTemplateInProject( buildDefinitionTemplateId,
1723                                                                 projectDao.getProject( project.getId() ) );
1724                }
1725 
1726                AbstractContinuumAction.setUnvalidatedProject( context, project );
1727                //
1728                //            executeAction( "validate-project", context );
1729                //
1730                //            executeAction( "store-project", context );
1731                //
1732                AbstractContinuumAction.setProjectId( context, project.getId() );
1733 
1734                if ( !StringUtils.isEmpty( scmUserName ) )
1735                {
1736                    project.setScmUsername( scmUserName );
1737                    CheckoutProjectContinuumAction.setScmUsername( context, scmUserName );
1738                }
1739                if ( !StringUtils.isEmpty( scmPassword ) )
1740                {
1741                    project.setScmPassword( scmPassword );
1742                    CheckoutProjectContinuumAction.setScmPassword( context, scmPassword );
1743                }
1744                // FIXME
1745                // olamy  : read again the project to have values because store.updateProjectGroup( projectGroup );
1746                // remove object data -> we don't display the project name in the build queue
1747                AbstractContinuumAction.setProject( context, projectDao.getProject( project.getId() ) );
1748 
1749                BuildDefinition defaultBuildDefinition = null;
1750                BuildDefinitionTemplate template = null;
1751                if ( projectBuilderId.equals( MavenTwoContinuumProjectBuilder.ID ) )
1752                {
1753                    template = buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate();
1754 
1755                    if( template != null && template.getBuildDefinitions().size() > 0 )
1756                    {
1757                        defaultBuildDefinition = template.getBuildDefinitions().get( 0 );
1758                    }
1759                }
1760                else if ( projectBuilderId.equals( MavenOneContinuumProjectBuilder.ID ) )
1761                {
1762                    template = buildDefinitionService.getDefaultMavenOneBuildDefinitionTemplate();
1763 
1764                    if ( template != null && template.getBuildDefinitions().size() > 0 )
1765                    {
1766                        defaultBuildDefinition = template.getBuildDefinitions().get( 0 );
1767                    }
1768                }
1769 
1770                if ( defaultBuildDefinition == null )
1771                {
1772                    // do not throw exception
1773                    // project already added so might as well continue with the rest
1774                    log.warn( "No default build definition found in the template. Project cannot be checked out." );
1775                }
1776                else
1777                {
1778                    // used by BuildManager to determine on which build queue will the project be put
1779                    AbstractContinuumAction.setBuildDefinition( context, defaultBuildDefinition );
1780    
1781                    if ( !configurationService.isDistributedBuildEnabled() )
1782                    {
1783                        executeAction( "add-project-to-checkout-queue", context );
1784                    }
1785                }
1786            }
1787        }
1788        catch ( BuildDefinitionServiceException e )
1789        {
1790            throw new ContinuumException( "Error attaching buildDefintionTemplate to project ", e );
1791        }
1792        catch ( ContinuumStoreException e )
1793        {
1794            throw new ContinuumException( "Error adding projects from modules", e );
1795        }
1796 
1797        AbstractContinuumAction.setProjectGroupId( context, projectGroup.getId() );
1798        // add the relevent security administration roles for this project
1799        if ( addAssignableRoles )
1800        {
1801            executeAction( "add-assignable-roles", context );
1802        }
1803        return result;
1804    }
1805 
1806    private ContinuumProjectBuildingResult executeAddProjectsFromMetadataActivity( String metadataUrl,
1807                                                                                   String projectBuilderId,
1808                                                                                   int projectGroupId,
1809                                                                                   boolean checkProtocol,
1810                                                                                   boolean useCredentialsCache,
1811                                                                                   boolean loadRecursiveProjects,
1812                                                                                   int buildDefinitionTemplateId )
1813        throws ContinuumException
1814    {
1815        return executeAddProjectsFromMetadataActivity( metadataUrl, projectBuilderId, projectGroupId, checkProtocol,
1816                                                       useCredentialsCache, loadRecursiveProjects,
1817                                                       buildDefinitionTemplateId, true );
1818    }
1819 
1820    // ----------------------------------------------------------------------
1821    // Notification
1822    // ----------------------------------------------------------------------
1823 
1824    // This whole section needs a scrub but will need to be dealt with generally
1825    // when we add schedules and profiles to the mix.
1826 
1827    public ProjectNotifier getNotifier( int projectId, int notifierId )
1828        throws ContinuumException
1829    {
1830        Project project = getProjectWithAllDetails( projectId );
1831 
1832        List<ProjectNotifier> notifiers = project.getNotifiers();
1833 
1834        ProjectNotifier notifier = null;
1835 
1836        for ( ProjectNotifier notif : notifiers )
1837        {
1838            notifier = notif;
1839 
1840            if ( notifier.getId() == notifierId )
1841            {
1842                break;
1843            }
1844        }
1845 
1846        return notifier;
1847    }
1848 
1849    public ProjectNotifier getGroupNotifier( int projectGroupId, int notifierId )
1850        throws ContinuumException
1851    {
1852        ProjectGroup projectGroup = getProjectGroupWithBuildDetails( projectGroupId );
1853 
1854        List<ProjectNotifier> notifiers = projectGroup.getNotifiers();
1855 
1856        ProjectNotifier notifier = null;
1857 
1858        for ( ProjectNotifier notif : notifiers )
1859        {
1860            notifier = notif;
1861 
1862            if ( notifier.getId() == notifierId )
1863            {
1864                break;
1865            }
1866        }
1867 
1868        return notifier;
1869    }
1870 
1871    public ProjectNotifier updateNotifier( int projectId, ProjectNotifier notifier )
1872        throws ContinuumException
1873    {
1874        Project project = getProjectWithAllDetails( projectId );
1875 
1876        ProjectNotifier notif = getNotifier( projectId, notifier.getId() );
1877 
1878        // I remove notifier then add it instead of update it due to a ClassCastException in jpox
1879        project.removeNotifier( notif );
1880 
1881        updateProject( project );
1882 
1883        return addNotifier( projectId, notifier );
1884    }
1885 
1886    public ProjectNotifier updateGroupNotifier( int projectGroupId, ProjectNotifier notifier )
1887        throws ContinuumException
1888    {
1889        ProjectGroup projectGroup = getProjectGroupWithBuildDetails( projectGroupId );
1890 
1891        ProjectNotifier notif = getGroupNotifier( projectGroupId, notifier.getId() );
1892 
1893        // I remove notifier then add it instead of update it due to a ClassCastException in jpox
1894        projectGroup.removeNotifier( notif );
1895 
1896        try
1897        {
1898            projectGroupDao.updateProjectGroup( projectGroup );
1899        }
1900        catch ( ContinuumStoreException cse )
1901        {
1902            throw new ContinuumException( "Unable to update project group.", cse );
1903        }
1904 
1905        return addGroupNotifier( projectGroupId, notifier );
1906    }
1907 
1908    public ProjectNotifier addNotifier( int projectId, ProjectNotifier notifier )
1909        throws ContinuumException
1910    {
1911        ProjectNotifier notif = new ProjectNotifier();
1912 
1913        notif.setSendOnSuccess( notifier.isSendOnSuccess() );
1914 
1915        notif.setSendOnFailure( notifier.isSendOnFailure() );
1916 
1917        notif.setSendOnError( notifier.isSendOnError() );
1918 
1919        notif.setSendOnWarning( notifier.isSendOnWarning() );
1920 
1921        notif.setSendOnScmFailure( notifier.isSendOnScmFailure() );
1922 
1923        notif.setConfiguration( notifier.getConfiguration() );
1924 
1925        notif.setType( notifier.getType() );
1926 
1927        notif.setFrom( ProjectNotifier.FROM_USER );
1928 
1929        Project project = getProjectWithAllDetails( projectId );
1930 
1931        project.addNotifier( notif );
1932 
1933        updateProject( project );
1934 
1935        return notif;
1936    }
1937 
1938    public ProjectNotifier addGroupNotifier( int projectGroupId, ProjectNotifier notifier )
1939        throws ContinuumException
1940    {
1941        ProjectNotifier notif = new ProjectNotifier();
1942 
1943        notif.setSendOnSuccess( notifier.isSendOnSuccess() );
1944 
1945        notif.setSendOnFailure( notifier.isSendOnFailure() );
1946 
1947        notif.setSendOnError( notifier.isSendOnError() );
1948 
1949        notif.setSendOnWarning( notifier.isSendOnWarning() );
1950 
1951        notif.setSendOnScmFailure( notifier.isSendOnScmFailure() );
1952 
1953        notif.setConfiguration( notifier.getConfiguration() );
1954 
1955        notif.setType( notifier.getType() );
1956 
1957        notif.setFrom( ProjectNotifier.FROM_USER );
1958 
1959        ProjectGroup projectGroup = getProjectGroupWithBuildDetails( projectGroupId );
1960 
1961        projectGroup.addNotifier( notif );
1962        try
1963        {
1964            projectGroupDao.updateProjectGroup( projectGroup );
1965        }
1966        catch ( ContinuumStoreException cse )
1967        {
1968            throw new ContinuumException( "unable to add notifier to project group", cse );
1969        }
1970 
1971        return notif;
1972    }
1973 
1974    public void removeNotifier( int projectId, int notifierId )
1975        throws ContinuumException
1976    {
1977        Project project = getProjectWithAllDetails( projectId );
1978 
1979        ProjectNotifier n = getNotifier( projectId, notifierId );
1980 
1981        if ( n != null )
1982        {
1983            if ( n.isFromProject() )
1984            {
1985                n.setEnabled( false );
1986 
1987                storeNotifier( n );
1988            }
1989            else
1990            {
1991                project.removeNotifier( n );
1992 
1993                updateProject( project );
1994            }
1995        }
1996    }
1997 
1998    public void removeGroupNotifier( int projectGroupId, int notifierId )
1999        throws ContinuumException
2000    {
2001        ProjectGroup projectGroup = getProjectGroupWithBuildDetails( projectGroupId );
2002 
2003        ProjectNotifier n = getGroupNotifier( projectGroupId, notifierId );
2004 
2005        if ( n != null )
2006        {
2007            if ( n.isFromProject() )
2008            {
2009                n.setEnabled( false );
2010 
2011                storeNotifier( n );
2012            }
2013            else
2014            {
2015                projectGroup.removeNotifier( n );
2016 
2017                try
2018                {
2019                    projectGroupDao.updateProjectGroup( projectGroup );
2020                }
2021                catch ( ContinuumStoreException cse )
2022                {
2023                    throw new ContinuumException( "Unable to remove notifer from project group.", cse );
2024                }
2025            }
2026        }
2027    }
2028 
2029    // ----------------------------------------------------------------------
2030    // Build Definition
2031    // ----------------------------------------------------------------------
2032 
2033    public List<BuildDefinition> getBuildDefinitions( int projectId )
2034        throws ContinuumException
2035    {
2036        Project project = getProjectWithAllDetails( projectId );
2037 
2038        return project.getBuildDefinitions();
2039    }
2040 
2041    public BuildDefinition getBuildDefinition( int projectId, int buildDefinitionId )
2042        throws ContinuumException
2043    {
2044        List<BuildDefinition> buildDefinitions = getBuildDefinitions( projectId );
2045 
2046        BuildDefinition buildDefinition = null;
2047 
2048        for ( BuildDefinition bd : buildDefinitions )
2049        {
2050            if ( bd.getId() == buildDefinitionId )
2051            {
2052                buildDefinition = bd;
2053                break;
2054            }
2055        }
2056 
2057        return buildDefinition;
2058    }
2059 
2060    public BuildDefinition getDefaultBuildDefinition( int projectId )
2061        throws ContinuumException
2062    {
2063        try
2064        {
2065            return buildDefinitionDao.getDefaultBuildDefinition( projectId );
2066        }
2067        catch ( ContinuumObjectNotFoundException cne )
2068        {
2069            throw new ContinuumException( "no default build definition for project", cne );
2070        }
2071        catch ( ContinuumStoreException cse )
2072        {
2073            throw new ContinuumException(
2074                "error attempting to access default build definition for project " + projectId, cse );
2075        }
2076    }
2077 
2078    public List<BuildDefinition> getDefaultBuildDefinitionsForProjectGroup( int projectGroupId )
2079        throws ContinuumException
2080    {
2081        try
2082        {
2083            return buildDefinitionDao.getDefaultBuildDefinitionsForProjectGroup( projectGroupId );
2084        }
2085        catch ( ContinuumObjectNotFoundException cne )
2086        {
2087            throw new ContinuumException( "Project Group (id=" + projectGroupId +
2088                " doens't have a default build definition, this should be impossible, it should always have a default definition set." );
2089        }
2090        catch ( ContinuumStoreException cse )
2091        {
2092            throw new ContinuumException( "Project Group (id=" + projectGroupId +
2093                " doens't have a default build definition, this should be impossible, it should always have a default definition set." );
2094        }
2095    }
2096 
2097    public BuildDefinition getBuildDefinition( int buildDefinitionId )
2098        throws ContinuumException
2099    {
2100        try
2101        {
2102            return buildDefinitionDao.getBuildDefinition( buildDefinitionId );
2103        }
2104        catch ( ContinuumObjectNotFoundException cne )
2105        {
2106            throw new ContinuumException( "no build definition found", cne );
2107        }
2108        catch ( ContinuumStoreException cse )
2109        {
2110            throw new ContinuumException( "error attempting to access build definition", cse );
2111        }
2112    }
2113 
2114    public List<BuildDefinition> getBuildDefinitionsForProject( int projectId )
2115        throws ContinuumException
2116    {
2117        Project project = getProjectWithAllDetails( projectId );
2118 
2119        return project.getBuildDefinitions();
2120    }
2121 
2122    public List<BuildDefinition> getBuildDefinitionsForProjectGroup( int projectGroupId )
2123        throws ContinuumException
2124    {
2125 
2126        ProjectGroup projectGroup = getProjectGroupWithBuildDetails( projectGroupId );
2127 
2128        return projectGroup.getBuildDefinitions();
2129    }
2130 
2131    public BuildDefinition addBuildDefinitionToProject( int projectId, BuildDefinition buildDefinition )
2132        throws ContinuumException
2133    {
2134        HashMap<String, Object> context = new HashMap<String, Object>();
2135        Schedule schedule = buildDefinition.getSchedule();
2136 
2137        AbstractContinuumAction.setBuildDefinition( context, buildDefinition );
2138        AbstractContinuumAction.setProjectId( context, projectId );
2139 
2140        executeAction( "add-build-definition-to-project", context );
2141 
2142        activeBuildDefinitionSchedule( schedule );
2143 
2144        return AbstractContinuumAction.getBuildDefinition( context );
2145    }
2146 
2147    public void removeBuildDefinitionFromProject( int projectId, int buildDefinitionId )
2148        throws ContinuumException
2149    {
2150        HashMap<String, Object> context = new HashMap<String, Object>();
2151        BuildDefinition buildDefinition = getBuildDefinition( buildDefinitionId );
2152 
2153        AbstractContinuumAction.setBuildDefinition( context, buildDefinition );
2154        AbstractContinuumAction.setProjectId( context, projectId );
2155 
2156        executeAction( "remove-build-definition-from-project", context );
2157    }
2158 
2159    public BuildDefinition updateBuildDefinitionForProject( int projectId, BuildDefinition buildDefinition )
2160        throws ContinuumException
2161    {
2162        HashMap<String, Object> context = new HashMap<String, Object>();
2163        Schedule schedule = buildDefinition.getSchedule();
2164 
2165        AbstractContinuumAction.setBuildDefinition( context, buildDefinition );
2166        AbstractContinuumAction.setProjectId( context, projectId );
2167 
2168        executeAction( "update-build-definition-from-project", context );
2169 
2170        activeBuildDefinitionSchedule( schedule );
2171 
2172        return AbstractContinuumAction.getBuildDefinition( context );
2173    }
2174 
2175    public BuildDefinition addBuildDefinitionToProjectGroup( int projectGroupId, BuildDefinition buildDefinition )
2176        throws ContinuumException
2177    {
2178        HashMap<String, Object> context = new HashMap<String, Object>();
2179        Schedule schedule = buildDefinition.getSchedule();
2180 
2181        AbstractContinuumAction.setBuildDefinition( context, buildDefinition );
2182        AbstractContinuumAction.setProjectGroupId( context, projectGroupId );
2183 
2184        executeAction( "add-build-definition-to-project-group", context );
2185 
2186        activeBuildDefinitionSchedule( schedule );
2187 
2188        return AbstractContinuumAction.getBuildDefinition( context );
2189    }
2190 
2191    public void removeBuildDefinitionFromProjectGroup( int projectGroupId, int buildDefinitionId )
2192        throws ContinuumException
2193    {
2194        HashMap<String, Object> context = new HashMap<String, Object>();
2195 
2196        AbstractContinuumAction.setBuildDefinition( context, getBuildDefinition( buildDefinitionId ) );
2197        AbstractContinuumAction.setProjectGroupId( context, projectGroupId );
2198 
2199        executeAction( "remove-build-definition-from-project-group", context );
2200    }
2201 
2202    public BuildDefinition updateBuildDefinitionForProjectGroup( int projectGroupId, BuildDefinition buildDefinition )
2203        throws ContinuumException
2204    {
2205        HashMap<String, Object> context = new HashMap<String, Object>();
2206        Schedule schedule = buildDefinition.getSchedule();
2207 
2208        AbstractContinuumAction.setBuildDefinition( context, buildDefinition );
2209        AbstractContinuumAction.setProjectGroupId( context, projectGroupId );
2210 
2211        executeAction( "update-build-definition-from-project-group", context );
2212 
2213        activeBuildDefinitionSchedule( schedule );
2214 
2215        return AbstractContinuumAction.getBuildDefinition( context );
2216    }
2217 
2218    public void removeBuildDefinition( int projectId, int buildDefinitionId )
2219        throws ContinuumException
2220    {
2221        Project project = getProjectWithAllDetails( projectId );
2222 
2223        BuildDefinition buildDefinition = getBuildDefinition( projectId, buildDefinitionId );
2224 
2225        if ( buildDefinition != null )
2226        {
2227            project.removeBuildDefinition( buildDefinition );
2228 
2229            updateProject( project );
2230        }
2231    }
2232 
2233    // ----------------------------------------------------------------------
2234    // Schedule
2235    // ----------------------------------------------------------------------
2236 
2237    public Schedule getSchedule( int scheduleId )
2238        throws ContinuumException
2239    {
2240        try
2241        {
2242            return scheduleDao.getSchedule( scheduleId );
2243        }
2244        catch ( Exception ex )
2245        {
2246            throw logAndCreateException( "Error while getting schedule.", ex );
2247        }
2248    }
2249 
2250    public Schedule getScheduleByName( String scheduleName )
2251        throws ContinuumException
2252    {
2253        try
2254        {
2255            return scheduleDao.getScheduleByName( scheduleName );
2256        }
2257        catch ( ContinuumStoreException e )
2258        {
2259            throw logAndCreateException( "Error while accessing the store.", e );
2260        }
2261    }
2262 
2263    public Collection<Schedule> getSchedules()
2264        throws ContinuumException
2265    {
2266        return scheduleDao.getAllSchedulesByName();
2267    }
2268 
2269    public void addSchedule( Schedule schedule )
2270        throws ContinuumException
2271    {
2272        Schedule s;
2273 
2274        s = getScheduleByName( schedule.getName() );
2275 
2276        if ( s != null )
2277        {
2278            throw logAndCreateException( "Can't create schedule. A schedule with the same name already exists.", null );
2279        }
2280 
2281        s = scheduleDao.addSchedule( schedule );
2282 
2283        try
2284        {
2285            schedulesActivator.activateSchedule( s, this );
2286        }
2287        catch ( SchedulesActivationException e )
2288        {
2289            throw new ContinuumException( "Error activating schedule " + s.getName() + ".", e );
2290        }
2291    }
2292 
2293    public void updateSchedule( Schedule schedule )
2294        throws ContinuumException
2295    {
2296        updateSchedule( schedule, true );
2297    }
2298 
2299    private void updateSchedule( Schedule schedule, boolean updateScheduler )
2300        throws ContinuumException
2301    {
2302 
2303        Schedule old = getSchedule( schedule.getId() );
2304 
2305        storeSchedule( schedule );
2306 
2307        if ( updateScheduler )
2308        {
2309            try
2310            {
2311                if ( schedule.isActive() )
2312                {
2313                    // I unactivate old shcedule (could change name) before if it's already active
2314                    schedulesActivator.unactivateSchedule( old, this );
2315 
2316                    schedulesActivator.activateSchedule( schedule, this );
2317                }
2318                else
2319                {
2320                    // Unactivate old because could change name in new schedule
2321                    schedulesActivator.unactivateSchedule( old, this );
2322                }
2323            }
2324            catch ( SchedulesActivationException e )
2325            {
2326                log.error( "Can't unactivate schedule. You need to restart Continuum.", e );
2327            }
2328        }
2329    }
2330 
2331    public void updateSchedule( int scheduleId, Map<String, String> configuration )
2332        throws ContinuumException
2333    {
2334        Schedule schedule = getSchedule( scheduleId );
2335 
2336        schedule.setName( configuration.get( "schedule.name" ) );
2337 
2338        schedule.setDescription( configuration.get( "schedule.description" ) );
2339 
2340        schedule.setCronExpression( configuration.get( "schedule.cronExpression" ) );
2341 
2342        schedule.setDelay( Integer.parseInt( configuration.get( "schedule.delay" ) ) );
2343 
2344        schedule.setActive( Boolean.valueOf( configuration.get( "schedule.active" ) ) );
2345 
2346        updateSchedule( schedule, true );
2347    }
2348 
2349    public void removeSchedule( int scheduleId )
2350        throws ContinuumException
2351    {
2352        Schedule schedule = getSchedule( scheduleId );
2353 
2354        try
2355        {
2356            schedulesActivator.unactivateSchedule( schedule, this );
2357        }
2358        catch ( SchedulesActivationException e )
2359        {
2360            log.error( "Can't unactivate the schedule. You need to restart Continuum.", e );
2361        }
2362 
2363        try
2364        {
2365            scheduleDao.removeSchedule( schedule );
2366        }
2367        catch ( Exception e )
2368        {
2369            log.error( "Can't remove the schedule.", e );
2370 
2371            try
2372            {
2373                schedulesActivator.activateSchedule( schedule, this );
2374            }
2375            catch ( SchedulesActivationException sae )
2376            {
2377                log.error( "Can't reactivate the schedule. You need to restart Continuum.", e );
2378            }
2379            throw new ContinuumException( "Can't remove the schedule", e );
2380        }
2381    }
2382 
2383    private Schedule storeSchedule( Schedule schedule )
2384        throws ContinuumException
2385    {
2386        try
2387        {
2388            return scheduleDao.storeSchedule( schedule );
2389        }
2390        catch ( ContinuumStoreException ex )
2391        {
2392            throw logAndCreateException( "Error while storing schedule.", ex );
2393        }
2394    }
2395 
2396    public void activePurgeSchedule( Schedule schedule )
2397    {
2398        try
2399        {
2400            schedulesActivator.activatePurgeSchedule( schedule, this );
2401        }
2402        catch ( SchedulesActivationException e )
2403        {
2404            log.error( "Can't activate schedule for purgeConfiguration" );
2405        }
2406    }
2407 
2408    public void activeBuildDefinitionSchedule( Schedule schedule )
2409    {
2410        try
2411        {
2412            schedulesActivator.activateBuildSchedule( schedule, this );
2413        }
2414        catch ( SchedulesActivationException e )
2415        {
2416            log.error( "Can't activate schedule for buildDefinition" );
2417        }
2418    }
2419    // ----------------------------------------------------------------------
2420    // Working copy
2421    // ----------------------------------------------------------------------
2422 
2423    public File getWorkingDirectory( int projectId )
2424        throws ContinuumException
2425    {
2426        try
2427        {
2428            return workingDirectoryService.getWorkingDirectory( projectDao.getProject( projectId ) );
2429        }
2430        catch ( ContinuumStoreException e )
2431        {
2432            throw new ContinuumException( "Can't get files list.", e );
2433        }
2434    }
2435 
2436    public String getFileContent( int projectId, String directory, String filename )
2437        throws ContinuumException
2438    {
2439        String relativePath = "\\.\\./"; // prevent users from using relative paths.
2440        Pattern pattern = Pattern.compile( relativePath );
2441        Matcher matcher = pattern.matcher( directory );
2442        String filteredDirectory = matcher.replaceAll( "" );
2443 
2444        matcher = pattern.matcher( filename );
2445        String filteredFilename = matcher.replaceAll( "" );
2446 
2447        File workingDirectory = getWorkingDirectory( projectId );
2448 
2449        File fileDirectory = new File( workingDirectory, filteredDirectory );
2450 
2451        File userFile = new File( fileDirectory, filteredFilename );
2452 
2453        try
2454        {
2455            return FileUtils.fileRead( userFile );
2456        }
2457        catch ( IOException e )
2458        {
2459            throw new ContinuumException( "Can't read file " + filename, e );
2460        }
2461    }
2462 
2463    public List<File> getFiles( int projectId, String userDirectory )
2464        throws ContinuumException
2465    {
2466        File workingDirectory = getWorkingDirectory( projectId );
2467 
2468        return getFiles( workingDirectory, null, userDirectory );
2469    }
2470 
2471    private List<File> getFiles( File baseDirectory, String currentSubDirectory, String userDirectory )
2472    {
2473        List<File> dirs = new ArrayList<File>();
2474 
2475        File workingDirectory;
2476 
2477        if ( currentSubDirectory != null )
2478        {
2479            workingDirectory = new File( baseDirectory, currentSubDirectory );
2480        }
2481        else
2482        {
2483            workingDirectory = baseDirectory;
2484        }
2485 
2486        String[] files = workingDirectory.list();
2487 
2488        if ( files != null )
2489        {
2490            for ( String file : files )
2491            {
2492                File current = new File( workingDirectory, file );
2493 
2494                String currentFile;
2495 
2496                if ( currentSubDirectory == null )
2497                {
2498                    currentFile = file;
2499                }
2500                else
2501                {
2502                    currentFile = currentSubDirectory + "/" + file;
2503                }
2504 
2505                if ( userDirectory != null && current.isDirectory() && userDirectory.startsWith( currentFile ) )
2506                {
2507                    dirs.add( current );
2508 
2509                    dirs.addAll( getFiles( baseDirectory, currentFile, userDirectory ) );
2510                }
2511                else
2512                {
2513                    dirs.add( current );
2514                }
2515            }
2516        }
2517 
2518        return dirs;
2519    }
2520 
2521    // ----------------------------------------------------------------------
2522    // Configuration
2523    // ----------------------------------------------------------------------
2524 
2525    public ConfigurationService getConfiguration()
2526    {
2527        return configurationService;
2528    }
2529 
2530    public void reloadConfiguration()
2531        throws ContinuumException
2532    {
2533        try
2534        {
2535            configurationService.reload();
2536        }
2537        catch ( Exception e )
2538        {
2539            throw new ContinuumException( "Can't reload configuration.", e );
2540        }
2541    }
2542 
2543    // ----------------------------------------------------------------------
2544    // Lifecycle Management
2545    // ----------------------------------------------------------------------
2546 
2547    public void initialize()
2548        throws InitializationException
2549    {
2550        log.info( "Initializing Continuum." );
2551 
2552        log.info( "Showing all groups:" );
2553        try
2554        {
2555            for ( ProjectGroup group : projectGroupDao.getAllProjectGroups() )
2556            {
2557                createProjectScmRootForProjectGroup( group );
2558            }
2559        }
2560        catch ( ContinuumException e )
2561        {
2562            throw new InitializationException( "Error while creating project scm root for the project group", e );
2563        }
2564 
2565        log.info( "Showing all projects: " );
2566 
2567        for ( Project project : projectDao.getAllProjectsByNameWithBuildDetails() )
2568        {
2569            for ( ProjectNotifier notifier : (List<ProjectNotifier>) project.getNotifiers() )
2570            {
2571                if ( StringUtils.isEmpty( notifier.getType() ) )
2572                {
2573                    try
2574                    {
2575                        removeNotifier( project.getId(), notifier.getId() );
2576                    }
2577                    catch ( ContinuumException e )
2578                    {
2579                        throw new InitializationException( "Database is corrupted.", e );
2580                    }
2581                }
2582            }
2583 
2584            if ( project.getState() != ContinuumProjectState.NEW &&
2585                project.getState() != ContinuumProjectState.CHECKEDOUT &&
2586                project.getState() != ContinuumProjectState.OK && project.getState() != ContinuumProjectState.FAILED &&
2587                project.getState() != ContinuumProjectState.ERROR )
2588            {
2589                int state = project.getState();
2590 
2591                project.setState( project.getOldState() );
2592 
2593                project.setOldState( 0 );
2594 
2595                try
2596                {
2597                    log.info( "Fix project state for project " + project.getId() + ":" + project.getName() + ":" +
2598                        project.getVersion() );
2599 
2600                    projectDao.updateProject( project );
2601 
2602                    Project p = projectDao.getProject( project.getId() );
2603 
2604                    if ( state == p.getState() )
2605                    {
2606                        log.info( "Can't fix the project state." );
2607                    }
2608                }
2609                catch ( ContinuumStoreException e )
2610                {
2611                    throw new InitializationException( "Database is corrupted.", e );
2612                }
2613            }
2614 
2615            log.info( " " + project.getId() + ":" + project.getName() + ":" + project.getVersion() + ":" +
2616                project.getExecutorId() );
2617        }
2618 
2619        for ( ProjectScmRoot projectScmRoot : projectScmRootDao.getAllProjectScmRoots() )
2620        {
2621            if ( projectScmRoot.getState() == ContinuumProjectState.UPDATING )
2622            {
2623                projectScmRoot.setState( projectScmRoot.getOldState() );
2624 
2625                projectScmRoot.setOldState( 0 );
2626 
2627                try
2628                {
2629                    log.info( "Fix state for projectScmRoot " + projectScmRoot.getScmRootAddress() );
2630 
2631                    projectScmRootDao.updateProjectScmRoot( projectScmRoot );
2632                }
2633                catch ( ContinuumStoreException e )
2634                {
2635                    throw new InitializationException( "Database is corrupted.", e );
2636                }
2637            }
2638        }
2639    }
2640 
2641    // --------------------------------
2642    //  Plexus Lifecycle
2643    // --------------------------------
2644    public void start()
2645        throws StartingException
2646    {
2647        startMessage();
2648 
2649        try
2650        {
2651            initializer.initialize();
2652 
2653            configurationService.reload();
2654        }
2655        catch ( ConfigurationLoadingException e )
2656        {
2657            throw new StartingException( "Error loading the Continuum configuration.", e );
2658        }
2659        catch ( ContinuumConfigurationException e )
2660        {
2661            throw new StartingException( "Error loading the Continuum configuration.", e );
2662        }
2663        catch ( ContinuumInitializationException e )
2664        {
2665            throw new StartingException( "Cannot initializing Continuum for the first time.", e );
2666        }
2667 
2668        try
2669        {
2670            // ----------------------------------------------------------------------
2671            // Activate all the schedules in the system
2672            // ----------------------------------------------------------------------
2673            schedulesActivator.activateSchedules( this );
2674        }
2675        catch ( SchedulesActivationException e )
2676        {
2677            // We don't throw an exception here, so users will can modify schedules in interface instead of database
2678            log.error( "Error activating schedules.", e );
2679        }
2680    }
2681 
2682    public void stop()
2683        throws StoppingException
2684    {
2685        stopContinuum();
2686    }
2687 
2688    private void closeStore()
2689    {
2690        if ( daoUtils != null )
2691        {
2692            daoUtils.closeStore();
2693        }
2694    }
2695 
2696 
2697    public void startup()
2698        throws ContinuumException
2699    {
2700        try
2701        {
2702            this.start();
2703        }
2704        catch ( StartingException e )
2705        {
2706            throw new ContinuumException( e.getMessage(), e );
2707        }
2708    }
2709 
2710    private void stopContinuum()
2711    {
2712        //TODO: Remove all projects from queues, stop scheduler and wait the end of current builds so build results will be ok
2713        if ( stopped )
2714        {
2715            return;
2716        }
2717 
2718        try
2719        {
2720            if ( configurationService != null )
2721            {
2722                configurationService.store();
2723            }
2724        }
2725        catch ( Exception e )
2726        {
2727            log.info( "Error storing the Continuum configuration.", e );
2728        }
2729 
2730        closeStore();
2731 
2732        stopMessage();
2733 
2734        stopped = true;
2735    }
2736 
2737    public long getNbBuildResultsForProject( int projectId )
2738    {
2739        return buildResultDao.getNbBuildResultsForProject( projectId );
2740    }
2741 
2742    public Collection<BuildResult> getBuildResultsForProject( int projectId )
2743        throws ContinuumException
2744    {
2745        return buildResultDao.getBuildResultsForProject( projectId );
2746    }
2747 
2748    // ----------------------------------------------------------------------
2749    // Workflow
2750    // ----------------------------------------------------------------------
2751 
2752    protected void executeAction( String actionName, Map<String, Object> context )
2753        throws ContinuumException
2754    {
2755        try
2756        {
2757            Action action = actionManager.lookup( actionName );
2758 
2759            action.execute( context );
2760        }
2761        catch ( ActionNotFoundException e )
2762        {
2763            e.printStackTrace();
2764            throw new ContinuumException( "Error while executing the action '" + actionName + "'.", e );
2765        }
2766        catch ( ContinuumException e )
2767        {
2768            throw e;
2769        }
2770        catch ( Exception e )
2771        {
2772            log.info( "exception", e );
2773            throw new ContinuumException( "Error while executing the action '" + actionName + "'.", e );
2774        }
2775    }
2776 
2777    // ----------------------------------------------------------------------
2778    // Logging
2779    // ----------------------------------------------------------------------
2780 
2781    private ContinuumException logAndCreateException( String message, Throwable cause )
2782    {
2783        if ( cause instanceof ContinuumObjectNotFoundException )
2784        {
2785            return new ContinuumException( "No such object.", cause );
2786        }
2787 
2788        log.error( message, cause );
2789 
2790        return new ContinuumException( message, cause );
2791    }
2792 
2793    // ----------------------------------------------------------------------
2794    // Build settings
2795    // ----------------------------------------------------------------------
2796 
2797    // core
2798 
2799    public void updateProject( Project project )
2800        throws ContinuumException
2801    {
2802        try
2803        {
2804            boolean removeWorkingDirectory = false;
2805 
2806            Project p = projectDao.getProject( project.getId() );
2807            ProjectScmRoot projectScmRoot = null;
2808 
2809            if ( !p.getScmUrl().equals( project.getScmUrl() ) )
2810            {
2811                removeWorkingDirectory = true;
2812                projectScmRoot = getProjectScmRootByProject( project.getId() );
2813            }
2814 
2815            if ( !p.getProjectGroup().equals( project.getProjectGroup() ) )
2816            {
2817                projectScmRoot = getProjectScmRootByProject( project.getId() );
2818            }
2819 
2820            if ( StringUtils.isEmpty( p.getScmTag() ) && !StringUtils.isEmpty( project.getScmTag() ) )
2821            {
2822                removeWorkingDirectory = true;
2823            }
2824            else if ( !StringUtils.isEmpty( p.getScmTag() ) && StringUtils.isEmpty( project.getScmTag() ) )
2825            {
2826                removeWorkingDirectory = true;
2827            }
2828            else if ( !StringUtils.isEmpty( p.getScmTag() ) && !p.getScmTag().equals( project.getScmTag() ) )
2829            {
2830                removeWorkingDirectory = true;
2831            }
2832 
2833            if ( removeWorkingDirectory )
2834            {
2835                File workingDirectory = getWorkingDirectory( project.getId() );
2836 
2837                FileUtils.deleteDirectory( workingDirectory );
2838            }
2839 
2840            if ( StringUtils.isEmpty( project.getScmTag() ) )
2841            {
2842                project.setScmTag( null );
2843            }
2844 
2845            projectDao.updateProject( project );
2846 
2847            if ( projectScmRoot != null )
2848            {
2849                updateProjectScmRoot( projectScmRoot, project );
2850            }
2851        }
2852        catch ( ContinuumStoreException ex )
2853        {
2854            throw logAndCreateException( "Error while updating project.", ex );
2855        }
2856        catch ( IOException ex )
2857        {
2858            throw logAndCreateException( "Error while updating project.", ex );
2859        }
2860    }
2861 
2862    public void updateProjectGroup( ProjectGroup projectGroup )
2863        throws ContinuumException
2864    {
2865        //CONTINUUM-1502
2866        projectGroup.setName( projectGroup.getName().trim() );
2867        try
2868        {
2869            projectGroupDao.updateProjectGroup( projectGroup );
2870        }
2871        catch ( ContinuumStoreException cse )
2872        {
2873            throw logAndCreateException( "Error while updating project group.", cse );
2874        }
2875    }
2876 
2877    private ProjectNotifier storeNotifier( ProjectNotifier notifier )
2878        throws ContinuumException
2879    {
2880        try
2881        {
2882            return notifierDao.storeNotifier( notifier );
2883        }
2884        catch ( ContinuumStoreException ex )
2885        {
2886            throw logAndCreateException( "Error while storing notifier.", ex );
2887        }
2888    }
2889 
2890    private String getWorkingDirectory()
2891    {
2892        return configurationService.getWorkingDirectory().getAbsolutePath();
2893    }
2894 
2895    public Project getProjectWithCheckoutResult( int projectId )
2896        throws ContinuumException
2897    {
2898        try
2899        {
2900            return projectDao.getProjectWithCheckoutResult( projectId );
2901        }
2902        catch ( ContinuumObjectNotFoundException e )
2903        {
2904            throw new ContinuumException( "Unable to find the requested project", e );
2905        }
2906        catch ( ContinuumStoreException e )
2907        {
2908            throw new ContinuumException( "Error retrieving the requested project", e );
2909        }
2910    }
2911 
2912    public Project getProjectWithAllDetails( int projectId )
2913        throws ContinuumException
2914    {
2915        try
2916        {
2917            return projectDao.getProjectWithAllDetails( projectId );
2918        }
2919        catch ( ContinuumObjectNotFoundException e )
2920        {
2921            throw new ContinuumException( "Unable to find the requested project", e );
2922        }
2923        catch ( ContinuumStoreException e )
2924        {
2925            throw new ContinuumException( "Error retrieving the requested project", e );
2926        }
2927    }
2928 
2929    public ProjectGroup getProjectGroupWithBuildDetails( int projectGroupId )
2930        throws ContinuumException
2931    {
2932        try
2933        {
2934            return projectGroupDao.getProjectGroupWithBuildDetailsByProjectGroupId( projectGroupId );
2935        }
2936        catch ( ContinuumObjectNotFoundException e )
2937        {
2938            throw new ContinuumException( "Unable to find the requested project", e );
2939        }
2940        catch ( ContinuumStoreException e )
2941        {
2942            throw new ContinuumException( "Error retrieving the requested project", e );
2943        }
2944    }
2945 
2946    public Project getProjectWithBuilds( int projectId )
2947        throws ContinuumException
2948    {
2949        try
2950        {
2951            return projectDao.getProjectWithBuilds( projectId );
2952        }
2953        catch ( ContinuumObjectNotFoundException e )
2954        {
2955            throw new ContinuumException( "Unable to find the requested project", e );
2956        }
2957        catch ( ContinuumStoreException e )
2958        {
2959            throw new ContinuumException( "Error retrieving the requested project", e );
2960        }
2961    }
2962 
2963    public List<ProjectGroup> getAllProjectGroupsWithBuildDetails()
2964    {
2965        return projectGroupDao.getAllProjectGroupsWithBuildDetails();
2966    }
2967 
2968    public Collection<Project> getProjectsInGroup( int projectGroupId )
2969        throws ContinuumException
2970    {
2971        try
2972        {
2973            return projectDao.getProjectsInGroup( projectGroupId );
2974        }
2975        catch ( ContinuumObjectNotFoundException e )
2976        {
2977            throw new ContinuumException( "Unable to find the requested project", e );
2978        }
2979        catch ( ContinuumStoreException e )
2980        {
2981            throw new ContinuumException( "Error retrieving the requested project", e );
2982        }
2983    }
2984 
2985    public Collection<Project> getProjectsInGroupWithDependencies( int projectGroupId )
2986        throws ContinuumException
2987    {
2988        try
2989        {
2990            return projectDao.getProjectsInGroupWithDependencies( projectGroupId );
2991        }
2992        catch ( ContinuumObjectNotFoundException e )
2993        {
2994            throw new ContinuumException( "Unable to find the requested project", e );
2995        }
2996        catch ( ContinuumStoreException e )
2997        {
2998            throw new ContinuumException( "Error retrieving the requested project", e );
2999        }
3000    }
3001 
3002    // ----------------------------------------------------------------------
3003    // Private Utilities
3004    // ----------------------------------------------------------------------
3005 
3006    private void startMessage()
3007    {
3008        log.info( "Starting Continuum." );
3009 
3010        // ----------------------------------------------------------------------
3011        //
3012        // ----------------------------------------------------------------------
3013 
3014        String banner = StringUtils.repeat( "-", getVersion().length() );
3015 
3016        log.info( "" );
3017        log.info( "" );
3018        log.info( "< Continuum " + getVersion() + " started! >" );
3019        log.info( "-----------------------" + banner );
3020        log.info( "       \\   ^__^" );
3021        log.info( "        \\  (oo)\\_______" );
3022        log.info( "           (__)\\       )\\/\\" );
3023        log.info( "               ||----w |" );
3024        log.info( "               ||     ||" );
3025        log.info( "" );
3026        log.info( "" );
3027    }
3028 
3029    private void stopMessage()
3030    {
3031        // Yes dorothy, this can happen!
3032        if ( log != null )
3033        {
3034            log.info( "Stopping Continuum." );
3035 
3036            log.info( "Continuum stopped." );
3037        }
3038    }
3039 
3040    private String getVersion()
3041    {
3042        InputStream resourceAsStream = null;
3043        try
3044        {
3045            Properties properties = new Properties();
3046 
3047            String name = "META-INF/maven/org.apache.continuum/continuum-core/pom.properties";
3048 
3049            resourceAsStream = getClass().getClassLoader().getResourceAsStream( name );
3050 
3051            if ( resourceAsStream == null )
3052            {
3053                return "unknown";
3054            }
3055 
3056            properties.load( resourceAsStream );
3057 
3058            return properties.getProperty( "version", "unknown" );
3059        }
3060        catch ( IOException e )
3061        {
3062            return "unknown";
3063        }
3064        finally
3065        {
3066            if ( resourceAsStream != null )
3067            {
3068                IOUtil.close( resourceAsStream );
3069            }
3070        }
3071    }
3072 
3073    public InstallationService getInstallationService()
3074    {
3075        return installationService;
3076    }
3077 
3078    public ProfileService getProfileService()
3079    {
3080        return profileService;
3081    }
3082 
3083    public BuildDefinitionService getBuildDefinitionService()
3084    {
3085        return buildDefinitionService;
3086    }
3087 
3088    public ContinuumReleaseResult addContinuumReleaseResult( ContinuumReleaseResult releaseResult )
3089        throws ContinuumException
3090    {
3091        try
3092        {
3093            return releaseResultDao.addContinuumReleaseResult( releaseResult );
3094        }
3095        catch ( ContinuumStoreException e )
3096        {
3097            throw new ContinuumException( "Error while adding continuumReleaseResult", e );
3098        }
3099    }
3100 
3101    public void removeContinuumReleaseResult( int releaseResultId )
3102        throws ContinuumException
3103    {
3104        ContinuumReleaseResult releaseResult = getContinuumReleaseResult( releaseResultId );
3105 
3106        try
3107        {
3108            releaseResultDao.removeContinuumReleaseResult( releaseResult );
3109        }
3110        catch ( ContinuumStoreException e )
3111        {
3112            throw new ContinuumException( "Error while deleting continuumReleaseResult: " + releaseResultId, e );
3113        }
3114 
3115        try
3116        {
3117            int projectGroupId = releaseResult.getProjectGroup().getId();
3118 
3119            String name = "releases-" + releaseResult.getStartTime();
3120 
3121            File releaseFile = getConfiguration().getReleaseOutputFile( projectGroupId, name );
3122 
3123            if ( releaseFile.exists() )
3124            {
3125                try
3126                {
3127                    FileUtils.forceDelete( releaseFile );
3128                }
3129                catch ( IOException e )
3130                {
3131                    throw new ContinuumException( "Can't delete " + releaseFile.getAbsolutePath(), e );
3132                }
3133            }
3134        }
3135        catch ( ConfigurationException e )
3136        {
3137            log.info( "skip error during cleanup release files " + e.getMessage(), e );
3138        }
3139    }
3140 
3141    public ContinuumReleaseResult getContinuumReleaseResult( int releaseResultId )
3142        throws ContinuumException
3143    {
3144        try
3145        {
3146            return releaseResultDao.getContinuumReleaseResult( releaseResultId );
3147        }
3148        catch ( ContinuumObjectNotFoundException e )
3149        {
3150            throw new ContinuumException( "No continuumReleaseResult found: " + releaseResultId );
3151        }
3152        catch ( ContinuumStoreException e )
3153        {
3154            throw new ContinuumException( "Error while retrieving continuumReleaseResult: " + releaseResultId, e );
3155        }
3156    }
3157 
3158    public List<ContinuumReleaseResult> getAllContinuumReleaseResults()
3159    {
3160        return releaseResultDao.getAllContinuumReleaseResults();
3161    }
3162 
3163    public List<ContinuumReleaseResult> getContinuumReleaseResultsByProjectGroup( int projectGroupId )
3164    {
3165        return releaseResultDao.getContinuumReleaseResultsByProjectGroup( projectGroupId );
3166    }
3167 
3168    public ContinuumReleaseResult getContinuumReleaseResult( int projectId, String releaseGoal, long startTime,
3169                                                             long endTime )
3170        throws ContinuumException
3171    {
3172        try
3173        {
3174            return releaseResultDao.getContinuumReleaseResult( projectId, releaseGoal, startTime, endTime );
3175        }
3176        catch ( ContinuumStoreException e )
3177        {
3178            throw new ContinuumException(
3179                "Error while retrieving continuumReleaseResult of projectId " + projectId + " with releaseGoal: " +
3180                    releaseGoal, e );
3181        }
3182    }
3183 
3184    public String getReleaseOutput( int releaseResultId )
3185        throws ContinuumException
3186    {
3187        ContinuumReleaseResult releaseResult = getContinuumReleaseResult( releaseResultId );
3188 
3189        ProjectGroup projectGroup = releaseResult.getProjectGroup();
3190 
3191        try
3192        {
3193            return configurationService.getReleaseOutput( projectGroup.getId(),
3194                                                          "releases-" + releaseResult.getStartTime() );
3195        }
3196        catch ( ConfigurationException e )
3197        {
3198            throw new ContinuumException( "Error while retrieving release output for release: " + releaseResultId );
3199        }
3200    }
3201 
3202    public List<ProjectScmRoot> getProjectScmRootByProjectGroup( int projectGroupId )
3203    {
3204        return projectScmRootDao.getProjectScmRootByProjectGroup( projectGroupId );
3205    }
3206 
3207    public ProjectScmRoot getProjectScmRoot( int projectScmRootId )
3208        throws ContinuumException
3209    {
3210        try
3211        {
3212            return projectScmRootDao.getProjectScmRoot( projectScmRootId );
3213        }
3214        catch ( ContinuumObjectNotFoundException e )
3215        {
3216            throw new ContinuumException( "No projectScmRoot found with the given id: " + projectScmRootId );
3217        }
3218        catch ( ContinuumStoreException e )
3219        {
3220            throw new ContinuumException( "Error while retrieving projectScmRoot ", e );
3221        }
3222    }
3223 
3224    public ProjectScmRoot getProjectScmRootByProject( int projectId )
3225        throws ContinuumException
3226    {
3227        Project project = getProject( projectId );
3228        ProjectGroup group = getProjectGroupByProjectId( projectId );
3229 
3230        List<ProjectScmRoot> scmRoots = getProjectScmRootByProjectGroup( group.getId() );
3231 
3232        for ( ProjectScmRoot scmRoot : scmRoots )
3233        {
3234            if ( project.getScmUrl() != null && project.getScmUrl().startsWith( scmRoot.getScmRootAddress() ) )
3235            {
3236                return scmRoot;
3237            }
3238        }
3239        return null;
3240    }
3241 
3242    public ProjectScmRoot getProjectScmRootByProjectGroupAndScmRootAddress( int projectGroupId, String scmRootAddress )
3243        throws ContinuumException
3244    {
3245        try
3246        {
3247            return projectScmRootDao.getProjectScmRootByProjectGroupAndScmRootAddress( projectGroupId, scmRootAddress );
3248        }
3249        catch ( ContinuumStoreException e )
3250        {
3251            throw new ContinuumException( "Error while retrieving project scm root for " + projectGroupId, e );
3252        }
3253    }
3254 
3255    private void removeProjectScmRoot( ProjectScmRoot projectScmRoot )
3256        throws ContinuumException
3257    {
3258        if ( projectScmRoot == null )
3259        {
3260            return;
3261        }
3262 
3263        //get all projects in the group
3264        ProjectGroup group = getProjectGroupWithProjects( projectScmRoot.getProjectGroup().getId() );
3265 
3266        List<Project> projects = group.getProjects();
3267 
3268        boolean found = false;
3269        for ( Project project : projects )
3270        {
3271            if ( project.getScmUrl() != null && project.getScmUrl().startsWith( projectScmRoot.getScmRootAddress() ) )
3272            {
3273                found = true;
3274                break;
3275            }
3276        }
3277 
3278        if ( !found )
3279        {
3280            log.info( "Removing project scm root '" + projectScmRoot.getScmRootAddress() + "'" );
3281            try
3282            {
3283                projectScmRootDao.removeProjectScmRoot( projectScmRoot );
3284            }
3285            catch ( ContinuumStoreException e )
3286            {
3287                log.error( "Failed to remove project scm root '" + projectScmRoot.getScmRootAddress() + "'", e );
3288                throw new ContinuumException(
3289                    "Error while removing project scm root '" + projectScmRoot.getScmRootAddress() + "'", e );
3290            }
3291        }
3292        else
3293        {
3294            log.info(
3295                "Project scm root '" + projectScmRoot.getScmRootAddress() + "' still has projects, not removing" );
3296        }
3297    }
3298 
3299    public BuildQueue addBuildQueue( BuildQueue buildQueue )
3300        throws ContinuumException
3301    {
3302        try
3303        {
3304            return buildQueueService.addBuildQueue( buildQueue );
3305        }
3306        catch ( BuildQueueServiceException e )
3307        {
3308            throw new ContinuumException( "Error adding build queue to the database.", e );
3309        }
3310    }
3311 
3312    public BuildQueue getBuildQueue( int buildQueueId )
3313        throws ContinuumException
3314    {
3315        try
3316        {
3317            return buildQueueService.getBuildQueue( buildQueueId );
3318        }
3319        catch ( BuildQueueServiceException e )
3320        {
3321            throw new ContinuumException( "Error retrieving build queue.", e );
3322        }
3323    }
3324 
3325    public BuildQueue getBuildQueueByName( String buildQueueName )
3326        throws ContinuumException
3327    {
3328        try
3329        {
3330            return buildQueueService.getBuildQueueByName( buildQueueName );
3331        }
3332        catch ( BuildQueueServiceException e )
3333        {
3334            throw new ContinuumException( "Error retrieving build queue.", e );
3335        }
3336    }
3337 
3338    public void removeBuildQueue( BuildQueue buildQueue )
3339        throws ContinuumException
3340    {
3341        try
3342        {
3343            buildQueueService.removeBuildQueue( buildQueue );
3344        }
3345        catch ( BuildQueueServiceException e )
3346        {
3347            throw new ContinuumException( "Error deleting build queue from database.", e );
3348        }
3349    }
3350 
3351    public BuildQueue storeBuildQueue( BuildQueue buildQueue )
3352        throws ContinuumException
3353    {
3354        try
3355        {
3356            return buildQueueService.updateBuildQueue( buildQueue );
3357        }
3358        catch ( BuildQueueServiceException e )
3359        {
3360            throw new ContinuumException( "Error updating build queue.", e );
3361        }
3362    }
3363 
3364    public List<BuildQueue> getAllBuildQueues()
3365        throws ContinuumException
3366    {
3367        try
3368        {
3369            return buildQueueService.getAllBuildQueues();
3370        }
3371        catch ( BuildQueueServiceException e )
3372        {
3373            throw new ContinuumException( "Error adding build queue.", e );
3374        }
3375    }
3376 
3377    private void prepareBuildProjects( Collection<Project> projects, List<BuildDefinition> bds,
3378                                       boolean checkDefaultBuildDefinitionForProject, int trigger )
3379        throws ContinuumException
3380    {
3381        Map<ProjectScmRoot, Map<Integer, Integer>> map = new HashMap<ProjectScmRoot, Map<Integer, Integer>>();
3382        List<ProjectScmRoot> sortedScmRoot = new ArrayList<ProjectScmRoot>();
3383 
3384        for ( Project project : projects )
3385        {
3386            int projectId = project.getId();
3387 
3388            try
3389            {
3390                // check if project already in queue
3391                if ( parallelBuildsManager.isInAnyBuildQueue( projectId ) ||
3392                    parallelBuildsManager.isProjectInAnyCurrentBuild( projectId ) ||
3393                    parallelBuildsManager.isInPrepareBuildQueue( projectId ) ||
3394                    parallelBuildsManager.isProjectCurrentlyPreparingBuild( projectId ) )
3395                {
3396                    continue;
3397                }
3398 
3399                if ( parallelBuildsManager.isInAnyCheckoutQueue( projectId ) )
3400                {
3401                    parallelBuildsManager.removeProjectFromCheckoutQueue( projectId );
3402                }
3403            }
3404            catch ( BuildManagerException e )
3405            {
3406                throw new ContinuumException( e.getMessage(), e );
3407            }
3408 
3409            int buildDefId = -1;
3410 
3411            if ( bds != null )
3412            {
3413                for ( BuildDefinition bd : bds )
3414                {
3415                    if ( project.getExecutorId().equals( bd.getType() ) || ( StringUtils.isEmpty( bd.getType() ) &&
3416                        ContinuumBuildExecutorConstants.MAVEN_TWO_BUILD_EXECUTOR.equals( project.getExecutorId() ) ) )
3417                    {
3418                        buildDefId = bd.getId();
3419                        break;
3420                    }
3421                }
3422            }
3423 
3424            if ( checkDefaultBuildDefinitionForProject )
3425            {
3426                BuildDefinition projectDefaultBD = null;
3427                try
3428                {
3429                    projectDefaultBD = buildDefinitionDao.getDefaultBuildDefinitionForProject( projectId );
3430                }
3431                catch ( ContinuumObjectNotFoundException e )
3432                {
3433                    log.debug( e.getMessage() );
3434                }
3435                catch ( ContinuumStoreException e )
3436                {
3437                    log.debug( e.getMessage() );
3438                }
3439 
3440                if ( projectDefaultBD != null )
3441                {
3442                    buildDefId = projectDefaultBD.getId();
3443                    log.debug( "Project " + project.getId() +
3444                        " has own default build definition, will use it instead of group's." );
3445                }
3446            }
3447 
3448            if ( buildDefId == -1 )
3449            {
3450                log.info( "Project " + projectId +
3451                    " don't have a default build definition defined in the project or project group, will not be included in group prepare." );
3452                continue;
3453            }
3454 
3455            ProjectScmRoot scmRoot = getProjectScmRootByProject( projectId );
3456 
3457            Map<Integer, Integer> projectsAndBuildDefinitionsMap = map.get( scmRoot );
3458 
3459            if ( projectsAndBuildDefinitionsMap == null )
3460            {
3461                projectsAndBuildDefinitionsMap = new HashMap<Integer, Integer>();
3462            }
3463 
3464            projectsAndBuildDefinitionsMap.put( projectId, buildDefId );
3465 
3466            map.put( scmRoot, projectsAndBuildDefinitionsMap );
3467 
3468            if ( !sortedScmRoot.contains( scmRoot ) )
3469            {
3470                sortedScmRoot.add( scmRoot );
3471            }
3472        }
3473 
3474        prepareBuildProjects( map, trigger, sortedScmRoot );
3475    }
3476 
3477    private void prepareBuildProjects( Collection<Project> projects, int buildDefinitionId, int trigger )
3478        throws ContinuumException
3479    {
3480        Map<ProjectScmRoot, Map<Integer, Integer>> map = new HashMap<ProjectScmRoot, Map<Integer, Integer>>();
3481        List<ProjectScmRoot> sortedScmRoot = new ArrayList<ProjectScmRoot>();
3482 
3483        for ( Project project : projects )
3484        {
3485            int projectId = project.getId();
3486 
3487            try
3488            {
3489                // check if project already in queue
3490                if ( parallelBuildsManager.isInAnyBuildQueue( projectId ) ||
3491                    parallelBuildsManager.isProjectInAnyCurrentBuild( projectId ) ||
3492                    parallelBuildsManager.isInPrepareBuildQueue( projectId ) ||
3493                    parallelBuildsManager.isProjectCurrentlyPreparingBuild( projectId ) )
3494                {
3495                    log.info( "not building" );
3496                    continue;
3497                }
3498 
3499                if ( parallelBuildsManager.isInAnyCheckoutQueue( projectId ) )
3500                {
3501                    parallelBuildsManager.removeProjectFromCheckoutQueue( projectId );
3502                }
3503 
3504                ProjectScmRoot scmRoot = getProjectScmRootByProject( projectId );
3505 
3506                Map<Integer, Integer> projectsAndBuildDefinitionsMap = map.get( scmRoot );
3507 
3508                if ( projectsAndBuildDefinitionsMap == null )
3509                {
3510                    projectsAndBuildDefinitionsMap = new HashMap<Integer, Integer>();
3511                }
3512 
3513                projectsAndBuildDefinitionsMap.put( projectId, buildDefinitionId );
3514 
3515                map.put( scmRoot, projectsAndBuildDefinitionsMap );
3516 
3517                if ( !sortedScmRoot.contains( scmRoot ) )
3518                {
3519                    sortedScmRoot.add( scmRoot );
3520                }
3521            }
3522            catch ( BuildManagerException e )
3523            {
3524                throw new ContinuumException( e.getMessage(), e );
3525            }
3526        }
3527 
3528        prepareBuildProjects( map, trigger, sortedScmRoot );
3529    }
3530 
3531    private void prepareBuildProjects( Map<ProjectScmRoot, Map<Integer, Integer>> map, int trigger,
3532                                       List<ProjectScmRoot> scmRoots )
3533        throws ContinuumException
3534    {
3535        for ( ProjectScmRoot scmRoot : scmRoots )
3536        {
3537            prepareBuildProjects( map.get( scmRoot ), trigger, scmRoot.getScmRootAddress(),
3538                                  scmRoot.getProjectGroup().getId(), scmRoot.getId() );
3539        }
3540    }
3541 
3542    private void prepareBuildProjects( Map<Integer, Integer> projectsBuildDefinitionsMap, int trigger,
3543                                       String scmRootAddress, int projectGroupId, int scmRootId )
3544        throws ContinuumException
3545    {
3546        ProjectGroup group = getProjectGroup( projectGroupId );
3547 
3548        try
3549        {
3550            if ( configurationService.isDistributedBuildEnabled() )
3551            {
3552                distributedBuildManager.prepareBuildProjects( projectsBuildDefinitionsMap, trigger, projectGroupId,
3553                                                              group.getName(), scmRootAddress, scmRootId );
3554            }
3555            else
3556            {
3557                parallelBuildsManager.prepareBuildProjects( projectsBuildDefinitionsMap, trigger, projectGroupId,
3558                                                            group.getName(), scmRootAddress, scmRootId );
3559            }
3560        }
3561        catch ( BuildManagerException e )
3562        {
3563            throw logAndCreateException( "Error while creating enqueuing object.", e );
3564        }
3565    }
3566 
3567    private void createProjectScmRootForProjectGroup( ProjectGroup projectGroup )
3568        throws ContinuumException
3569    {
3570        List<Project> projectsList;
3571 
3572        projectsList =
3573            getProjectsInBuildOrder( projectDao.getProjectsWithDependenciesByGroupId( projectGroup.getId() ) );
3574 
3575        String url = "";
3576 
3577        for ( Project project : projectsList )
3578        {
3579            if ( StringUtils.isEmpty( url ) || !project.getScmUrl().startsWith( url ) )
3580            {
3581                // this is a root
3582                url = project.getScmUrl();
3583                createProjectScmRoot( projectGroup, url );
3584            }
3585        }
3586    }
3587 
3588    private ProjectScmRoot createProjectScmRoot( ProjectGroup projectGroup, String url )
3589        throws ContinuumException
3590    {
3591        try
3592        {
3593            ProjectScmRoot scmRoot =
3594                projectScmRootDao.getProjectScmRootByProjectGroupAndScmRootAddress( projectGroup.getId(), url );
3595 
3596            if ( scmRoot != null )
3597            {
3598                return null;
3599            }
3600 
3601            ProjectScmRoot projectScmRoot = new ProjectScmRoot();
3602 
3603            projectScmRoot.setProjectGroup( projectGroup );
3604 
3605            projectScmRoot.setScmRootAddress( url );
3606 
3607            return projectScmRootDao.addProjectScmRoot( projectScmRoot );
3608        }
3609        catch ( ContinuumStoreException e )
3610        {
3611            throw new ContinuumException( "Error while creating project scm root with scm root address:" + url );
3612        }
3613    }
3614 
3615    private void updateProjectScmRoot( ProjectScmRoot oldScmRoot, Project project )
3616        throws ContinuumException
3617    {
3618        try
3619        {
3620            removeProjectScmRoot( oldScmRoot );
3621            ProjectScmRoot scmRoot =
3622                projectScmRootDao.getProjectScmRootByProjectGroupAndScmRootAddress( project.getProjectGroup().getId(),
3623                                                                                    project.getScmUrl() );
3624            if ( scmRoot == null )
3625            {
3626                ProjectScmRoot newScmRoot = new ProjectScmRoot();
3627                if ( project.getScmUrl().equals( oldScmRoot.getScmRootAddress() ) )
3628                {
3629                    BeanUtils.copyProperties( oldScmRoot, newScmRoot, new String[]{"id", "projectGroup"} );
3630                }
3631                else
3632                {
3633                    newScmRoot.setScmRootAddress( project.getScmUrl() );
3634                }
3635                newScmRoot.setProjectGroup( project.getProjectGroup() );
3636                projectScmRootDao.addProjectScmRoot( newScmRoot );
3637            }
3638        }
3639        catch ( ContinuumStoreException ex )
3640        {
3641            throw logAndCreateException( "Error while updating project.", ex );
3642        }
3643    }
3644 
3645    private boolean isProjectInReleaseStage( Project project )
3646        throws ContinuumException
3647    {
3648        String releaseId = project.getGroupId() + ":" + project.getArtifactId();
3649        try
3650        {
3651            return taskQueueManager.isProjectInReleaseStage( releaseId );
3652        }
3653        catch ( TaskQueueManagerException e )
3654        {
3655            throw new ContinuumException( "Error occurred while checking if project is currently being released.", e );
3656        }
3657    }
3658 
3659    private boolean isAnyProjectInGroupInReleaseStage( int projectGroupId )
3660        throws ContinuumException
3661    {
3662        Collection<Project> projects = getProjectsInGroup( projectGroupId );
3663        for ( Project project : projects )
3664        {
3665            if ( isProjectInReleaseStage( project ) )
3666            {
3667                throw new ContinuumException( "Cannot build project group. Project (id=" + project.getId() +
3668                    ") in group is currently in release stage." );
3669            }
3670        }
3671        return false;
3672    }
3673 
3674    private boolean isAnyProjectsInReleaseStage( List<Project> projects )
3675        throws ContinuumException
3676    {
3677        for ( Project project : projects )
3678        {
3679            if ( isProjectInReleaseStage( project ) )
3680            {
3681                return true;
3682            }
3683        }
3684 
3685        return false;
3686    }
3687 
3688    private Collection<Project> getProjectsNotInReleaseStage( Collection<Project> projectsList )
3689        throws ContinuumException
3690    {
3691        // filter the projects to be built
3692        // projects that are in the release stage will not be built
3693        Collection<Project> filteredProjectsList = new ArrayList<Project>();
3694        for ( Project project : projectsList )
3695        {
3696            if ( !isProjectInReleaseStage( project ) )
3697            {
3698                filteredProjectsList.add( project );
3699            }
3700            else
3701            {
3702                log.warn(
3703                    "Project (id=" + project.getId() + ") will not be built. It is currently in the release stage." );
3704            }
3705        }
3706        return filteredProjectsList;
3707    }
3708 
3709    private void checkForDuplicateProjectInGroup( ProjectGroup projectGroup, Project projectToCheck,
3710                                                  ContinuumProjectBuildingResult result )
3711    {
3712        List<Project> projectsInGroup = projectGroup.getProjects();
3713 
3714        if ( projectsInGroup == null )
3715        {
3716            return;
3717        }
3718 
3719        for ( Project project : projectGroup.getProjects() )
3720        {
3721            // projectToCheck is first in the equals check, as projectToCheck must be a Maven project and will have
3722            // non-null values for each. project may be an Ant or Shell project and have null values.
3723            if ( projectToCheck.getGroupId().equals( project.getGroupId() ) && projectToCheck.getArtifactId().equals(
3724                project.getArtifactId() ) && projectToCheck.getVersion().equals( project.getVersion() ) )
3725            {
3726                result.addError( ContinuumProjectBuildingResult.ERROR_DUPLICATE_PROJECTS );
3727                return;
3728            }
3729        }
3730    }
3731 
3732    void setTaskQueueManager( TaskQueueManager taskQueueManager )
3733    {
3734        this.taskQueueManager = taskQueueManager;
3735    }
3736 
3737    void setProjectDao( ProjectDao projectDao )
3738    {
3739        this.projectDao = projectDao;
3740    }
3741 
3742    public DistributedBuildManager getDistributedBuildManager()
3743    {
3744        return distributedBuildManager;
3745    }
3746}

[all classes][org.apache.maven.continuum]
EMMA 2.0.5312 (C) Vladimir Roubtsov