View Javadoc

1   package org.apache.continuum.builder.distributed.manager;
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  
22  import org.apache.continuum.buildagent.NoBuildAgentException;
23  import org.apache.continuum.buildagent.NoBuildAgentInGroupException;
24  import org.apache.continuum.builder.distributed.executor.ThreadedDistributedBuildTaskQueueExecutor;
25  import org.apache.continuum.builder.distributed.util.DistributedBuildUtil;
26  import org.apache.continuum.builder.utils.ContinuumBuildConstant;
27  import org.apache.continuum.configuration.BuildAgentConfiguration;
28  import org.apache.continuum.configuration.BuildAgentGroupConfiguration;
29  import org.apache.continuum.dao.BuildDefinitionDao;
30  import org.apache.continuum.dao.BuildResultDao;
31  import org.apache.continuum.dao.ProjectDao;
32  import org.apache.continuum.dao.ProjectScmRootDao;
33  import org.apache.continuum.distributed.transport.slave.SlaveBuildAgentTransportClient;
34  import org.apache.continuum.distributed.transport.slave.SlaveBuildAgentTransportService;
35  import org.apache.continuum.model.project.ProjectRunSummary;
36  import org.apache.continuum.model.project.ProjectScmRoot;
37  import org.apache.continuum.taskqueue.BuildProjectTask;
38  import org.apache.continuum.taskqueue.OverallDistributedBuildQueue;
39  import org.apache.continuum.taskqueue.PrepareBuildProjectsTask;
40  import org.apache.continuum.utils.ContinuumUtils;
41  import org.apache.continuum.utils.ProjectSorter;
42  import org.apache.continuum.utils.build.BuildTrigger;
43  import org.apache.maven.continuum.ContinuumException;
44  import org.apache.maven.continuum.configuration.ConfigurationService;
45  import org.apache.maven.continuum.model.project.BuildDefinition;
46  import org.apache.maven.continuum.model.project.BuildResult;
47  import org.apache.maven.continuum.model.project.Project;
48  import org.apache.maven.continuum.model.system.Installation;
49  import org.apache.maven.continuum.model.system.Profile;
50  import org.apache.maven.continuum.project.ContinuumProjectState;
51  import org.apache.maven.continuum.store.ContinuumStoreException;
52  import org.codehaus.plexus.PlexusConstants;
53  import org.codehaus.plexus.PlexusContainer;
54  import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
55  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
56  import org.codehaus.plexus.context.Context;
57  import org.codehaus.plexus.context.ContextException;
58  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
59  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
60  import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
61  import org.codehaus.plexus.personality.plexus.lifecycle.phase.StoppingException;
62  import org.codehaus.plexus.taskqueue.Task;
63  import org.codehaus.plexus.taskqueue.TaskQueueException;
64  import org.codehaus.plexus.util.StringUtils;
65  import org.slf4j.Logger;
66  import org.slf4j.LoggerFactory;
67  
68  import java.net.MalformedURLException;
69  import java.net.URL;
70  import java.util.ArrayList;
71  import java.util.Collections;
72  import java.util.Date;
73  import java.util.HashMap;
74  import java.util.List;
75  import java.util.Map;
76  
77  /**
78   * @author Maria Catherine Tan
79   * @plexus.component role="org.apache.continuum.builder.distributed.manager.DistributedBuildManager"
80   */
81  public class DefaultDistributedBuildManager
82      implements DistributedBuildManager, Contextualizable, Initializable
83  {
84      private static final Logger log = LoggerFactory.getLogger( DefaultDistributedBuildManager.class );
85  
86      private Map<String, OverallDistributedBuildQueue> overallDistributedBuildQueues = Collections.synchronizedMap(
87          new HashMap<String, OverallDistributedBuildQueue>() );
88  
89      private List<ProjectRunSummary> currentRuns = Collections.synchronizedList( new ArrayList<ProjectRunSummary>() );
90  
91      /**
92       * @plexus.requirement
93       */
94      private ConfigurationService configurationService;
95  
96      /**
97       * @plexus.requirement
98       */
99      private ProjectDao projectDao;
100 
101     /**
102      * @plexus.requirement
103      */
104     private BuildDefinitionDao buildDefinitionDao;
105 
106     /**
107      * @plexus.requirement
108      */
109     private BuildResultDao buildResultDao;
110 
111     /**
112      * @plexus.requirement
113      */
114     private ProjectScmRootDao projectScmRootDao;
115 
116     /**
117      * @plexus.requirement
118      */
119     private DistributedBuildUtil distributedBuildUtil;
120 
121     private PlexusContainer container;
122 
123     // --------------------------------
124     //  Plexus Lifecycle
125     // --------------------------------
126     public void contextualize( Context context )
127         throws ContextException
128     {
129         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
130     }
131 
132     public void initialize()
133         throws InitializationException
134     {
135         List<BuildAgentConfiguration> agents = configurationService.getBuildAgents();
136 
137         if ( agents != null )
138         {
139             synchronized ( overallDistributedBuildQueues )
140             {
141                 for ( BuildAgentConfiguration agent : agents )
142                 {
143                     if ( agent.isEnabled() )
144                     {
145                         try
146                         {
147                             SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
148                                 agent.getUrl() );
149 
150                             if ( client.ping() )
151                             {
152                                 log.debug( "agent is enabled, create distributed build queue for build agent '{}'",
153                                            agent.getUrl() );
154                                 createDistributedBuildQueueForAgent( agent.getUrl() );
155                             }
156                             else
157                             {
158                                 log.debug( "unable to ping build agent '{}'", agent.getUrl() );
159                             }
160                         }
161                         catch ( MalformedURLException e )
162                         {
163                             // do not throw exception, just log it
164                             log.error( "Invalid build agent URL {}, not creating distributed build queue",
165                                        agent.getUrl() );
166                         }
167                         catch ( ContinuumException e )
168                         {
169                             throw new InitializationException( "Error while initializing distributed build queues", e );
170                         }
171                         catch ( Exception e )
172                         {
173                             agent.setEnabled( false );
174                             log.debug( "unable to ping build agent '{}' : {}", agent.getUrl(),
175                                        ContinuumUtils.throwableToString( e ) );
176                         }
177                     }
178                     else
179                     {
180                         log.debug( "agent {} is disabled, not creating distributed build queue", agent.getUrl() );
181                     }
182                 }
183             }
184         }
185     }
186 
187     public void reload()
188         throws ContinuumException
189     {
190         List<BuildAgentConfiguration> agents = configurationService.getBuildAgents();
191 
192         if ( agents == null )
193         {
194             return;
195         }
196 
197         synchronized ( overallDistributedBuildQueues )
198         {
199             for ( BuildAgentConfiguration agent : agents )
200             {
201                 if ( agent.isEnabled() && !overallDistributedBuildQueues.containsKey( agent.getUrl() ) )
202                 {
203                     SlaveBuildAgentTransportService client = null;
204 
205                     try
206                     {
207                         client = createSlaveBuildAgentTransportClientConnection( agent.getUrl() );
208                     }
209                     catch ( MalformedURLException e )
210                     {
211                         log.error( "Invalid build agent URL {}, not creating distributed build queue", agent.getUrl() );
212                         throw new ContinuumException( "Malformed build agent url " + agent.getUrl() );
213                     }
214                     catch ( Exception e )
215                     {
216                         agent.setEnabled( false );
217                         configurationService.updateBuildAgent( agent );
218 
219                         log.error( "Error binding build agent {} service : {} ", agent.getUrl(),
220                                    ContinuumUtils.throwableToString( e ) );
221                         throw new ContinuumException( e.getMessage() );
222                     }
223 
224                     boolean ping = false;
225 
226                     try
227                     {
228                         ping = client.ping();
229                     }
230                     catch ( Exception e )
231                     {
232                         agent.setEnabled( false );
233                         log.error( "Unable to ping build agent '{}': {}", agent.getUrl(),
234                                    ContinuumUtils.throwableToString( e ) );
235                     }
236 
237                     if ( ping )
238                     {
239                         try
240                         {
241                             createDistributedBuildQueueForAgent( agent.getUrl() );
242                             log.debug( "Agent is enabled, create distributed build queue for build agent '{}'",
243                                        agent.getUrl() );
244                         }
245                         catch ( Exception e )
246                         {
247                             agent.setEnabled( false );
248                             log.error( "Unable to create distributed queue for build agent {} : {}", agent.getUrl(),
249                                        ContinuumUtils.throwableToString( e ) );
250                         }
251                     }
252                     else
253                     {
254                         agent.setEnabled( false );
255                         log.error( "Unable to ping build agent '{}'", agent.getUrl() );
256                     }
257 
258                     configurationService.updateBuildAgent( agent );
259                 }
260                 else if ( !agent.isEnabled() && overallDistributedBuildQueues.containsKey( agent.getUrl() ) )
261                 {
262                     log.debug( "agent is disabled, remove distributed build queue for build agent '{}'",
263                                agent.getUrl() );
264                     removeDistributedBuildQueueOfAgent( agent.getUrl() );
265                 }
266             }
267         }
268     }
269 
270     public void update( BuildAgentConfiguration agent )
271         throws ContinuumException
272     {
273         synchronized ( overallDistributedBuildQueues )
274         {
275             if ( agent.isEnabled() && !overallDistributedBuildQueues.containsKey( agent.getUrl() ) )
276             {
277                 SlaveBuildAgentTransportService client;
278 
279                 try
280                 {
281                     client = createSlaveBuildAgentTransportClientConnection( agent.getUrl() );
282                 }
283                 catch ( MalformedURLException e )
284                 {
285                     log.error( "Invalid build agent URL {}, not creating distributed build queue", agent.getUrl() );
286                     throw new ContinuumException( "Malformed build agent url " + agent.getUrl() );
287                 }
288                 catch ( Exception e )
289                 {
290                     log.error( "Error binding build agent {} service : {} ", agent.getUrl(),
291                                ContinuumUtils.throwableToString( e ) );
292                     throw new ContinuumException( e.getMessage() );
293                 }
294 
295                 boolean ping;
296 
297                 try
298                 {
299                     ping = client.ping();
300                 }
301                 catch ( Exception e )
302                 {
303                     log.error( "Unable to ping build agent '{}': {}", agent.getUrl(), ContinuumUtils.throwableToString(
304                         e ) );
305                     throw new ContinuumException( "Unable to ping build agent " + agent.getUrl() );
306                 }
307 
308                 if ( ping )
309                 {
310                     try
311                     {
312                         createDistributedBuildQueueForAgent( agent.getUrl() );
313                         log.debug( "Agent is enabled, create distributed build queue for build agent '{}'",
314                                    agent.getUrl() );
315                     }
316                     catch ( Exception e )
317                     {
318                         log.error( "Unable to create distributed queue for build agent {} : {}", agent.getUrl(),
319                                    ContinuumUtils.throwableToString( e ) );
320                     }
321                 }
322                 else
323                 {
324                     log.error( "Unable to ping build agent '{}'", agent.getUrl() );
325                     throw new ContinuumException( "Unable to ping build agent " + agent.getUrl() );
326                 }
327             }
328             else if ( !agent.isEnabled() && overallDistributedBuildQueues.containsKey( agent.getUrl() ) )
329             {
330                 log.debug( "agent is disabled, remove distributed build queue for build agent '{}'", agent.getUrl() );
331                 removeDistributedBuildQueueOfAgent( agent.getUrl() );
332             }
333         }
334     }
335 
336     @SuppressWarnings( "unused" )
337     public void prepareBuildProjects( Map<Integer, Integer> projectsBuildDefinitionsMap, BuildTrigger buildTrigger,
338                                       int projectGroupId, String projectGroupName, String scmRootAddress, int scmRootId,
339                                       List<ProjectScmRoot> scmRoots )
340         throws ContinuumException, NoBuildAgentException, NoBuildAgentInGroupException
341     {
342         PrepareBuildProjectsTask task = new PrepareBuildProjectsTask( projectsBuildDefinitionsMap, buildTrigger,
343                                                                       projectGroupId, projectGroupName, scmRootAddress,
344                                                                       scmRootId );
345 
346         if ( buildTrigger.getTrigger() == ContinuumProjectState.TRIGGER_FORCED )
347         {
348             log.debug( "Build project (projectGroupId={}) triggered manually by {}", projectGroupId,
349                        buildTrigger.getTriggeredBy() );
350         }
351         else
352         {
353             log.debug( "Build project (projectGroupId={}) triggered by schedule {}", projectGroupId,
354                        buildTrigger.getTriggeredBy() );
355         }
356 
357         if ( log.isDebugEnabled() )
358         {
359             Map<String, BuildProjectTask> buildTasks = getProjectsCurrentlyBuilding();
360 
361             for ( String key : buildTasks.keySet() )
362             {
363                 log.debug( "Current build of agent {} :: Project {}", key, buildTasks.get( key ).getProjectName() );
364             }
365 
366             Map<String, List<BuildProjectTask>> buildQueues = getProjectsInBuildQueue();
367 
368             for ( String key : buildQueues.keySet() )
369             {
370                 for ( BuildProjectTask buildTask : buildQueues.get( key ) )
371                 {
372                     log.debug( "Build Queue of agent {} :: Project {}", key, buildTask.getProjectName() );
373                 }
374             }
375 
376             Map<String, PrepareBuildProjectsTask> prepareBuildTasks = getProjectsCurrentlyPreparingBuild();
377 
378             for ( String key : prepareBuildTasks.keySet() )
379             {
380                 PrepareBuildProjectsTask prepareBuildTask = prepareBuildTasks.get( key );
381                 log.debug( "Current prepare build of agent {} :: Project Group {} - Scm Root {}",
382                            new Object[]{key, prepareBuildTask.getProjectGroupName(),
383                                prepareBuildTask.getProjectScmRootId()} );
384             }
385 
386             Map<String, List<PrepareBuildProjectsTask>> prepareBuildQueues = getProjectsInPrepareBuildQueue();
387 
388             for ( String key : prepareBuildQueues.keySet() )
389             {
390                 for ( PrepareBuildProjectsTask prepareBuildTask : prepareBuildQueues.get( key ) )
391                 {
392                     log.debug( "Prepare Build Queue of agent {} : Project Group {} - Scm Root {}",
393                                new Object[]{key, prepareBuildTask.getProjectGroupName(),
394                                    prepareBuildTask.getProjectScmRootId()} );
395                 }
396             }
397         }
398 
399         log.debug( "Determining which build agent should build the project..." );
400 
401         OverallDistributedBuildQueue overallDistributedBuildQueue = getOverallDistributedBuildQueueByGroup(
402             projectGroupId, scmRoots, scmRootId );
403 
404         if ( overallDistributedBuildQueue == null )
405         {
406             log.debug(
407                 "No projects with the same continuum group is currently building, checking if build definition has an attached build agent group" );
408 
409             if ( hasBuildagentGroup( projectsBuildDefinitionsMap ) )
410             {
411                 log.debug(
412                     "Build definition used has an attached build agent group, checking if there are configured build agents in the group" );
413 
414                 if ( !hasBuildagentInGroup( projectsBuildDefinitionsMap ) )
415                 {
416                     log.warn( "No build agent configured in build agent group. Not building projects." );
417 
418                     throw new NoBuildAgentInGroupException( "No build agent configured in build agent group" );
419                 }
420                 else
421                 {
422                     // get overall distributed build queue from build agent group
423                     log.info( "Getting the least busy build agent within the build agent group" );
424                     overallDistributedBuildQueue = getOverallDistributedBuildQueueByAgentGroup(
425                         projectsBuildDefinitionsMap );
426                 }
427             }
428             else
429             {
430                 // project does not have build agent group
431                 log.info( "Project does not have a build agent group, getting the least busy of all build agents" );
432                 overallDistributedBuildQueue = getOverallDistributedBuildQueue();
433             }
434         }
435 
436         if ( overallDistributedBuildQueue != null )
437         {
438             try
439             {
440                 String agentUrl = overallDistributedBuildQueue.getBuildAgentUrl();
441                 log.info( "Building project in the least busy agent {}", agentUrl );
442                 overallDistributedBuildQueue.addToDistributedBuildQueue( task );
443                 createProjectRunSummaries( task, agentUrl );
444             }
445             catch ( TaskQueueException e )
446             {
447                 log.error( "Error while enqueuing prepare build task", e );
448                 throw new ContinuumException( "Error occurred while enqueuing prepare build task", e );
449             }
450         }
451         else
452         {
453             log.warn(
454                 "Unable to determine which build agent should build the project. No build agent configured. Not building projects." );
455 
456             throw new NoBuildAgentException( "No build agent configured" );
457         }
458 
459         // call in case we disabled a build agent
460         reload();
461     }
462 
463     public void removeDistributedBuildQueueOfAgent( String buildAgentUrl )
464         throws ContinuumException
465     {
466         if ( overallDistributedBuildQueues.containsKey( buildAgentUrl ) )
467         {
468             List<PrepareBuildProjectsTask> tasks = null;
469 
470             synchronized ( overallDistributedBuildQueues )
471             {
472                 OverallDistributedBuildQueue overallDistributedBuildQueue = overallDistributedBuildQueues.get(
473                     buildAgentUrl );
474 
475                 try
476                 {
477                     if ( overallDistributedBuildQueue.getDistributedBuildTaskQueueExecutor().getCurrentTask() != null )
478                     {
479                         log.error( "Unable to remove build agent because it is currently being used" );
480                         throw new ContinuumException(
481                             "Unable to remove build agent because it is currently being used" );
482                     }
483 
484                     tasks = overallDistributedBuildQueue.getProjectsInQueue();
485 
486                     overallDistributedBuildQueue.getDistributedBuildQueue().removeAll( tasks );
487 
488                     ( (ThreadedDistributedBuildTaskQueueExecutor) overallDistributedBuildQueue.getDistributedBuildTaskQueueExecutor() ).stop();
489 
490                     container.release( overallDistributedBuildQueue );
491 
492                     overallDistributedBuildQueues.remove( buildAgentUrl );
493 
494                     log.debug( "remove distributed build queue for build agent '{}'", buildAgentUrl );
495                 }
496                 catch ( TaskQueueException e )
497                 {
498                     log.error( "Error occurred while removing build agent {}", buildAgentUrl, e );
499                     throw new ContinuumException( "Error occurred while removing build agent " + buildAgentUrl, e );
500                 }
501                 catch ( ComponentLifecycleException e )
502                 {
503                     log.error( "Error occurred while removing build agent {}", buildAgentUrl, e );
504                     throw new ContinuumException( "Error occurred while removing build agent " + buildAgentUrl, e );
505                 }
506                 catch ( StoppingException e )
507                 {
508                     log.error( "Error occurred while removing build agent {}", buildAgentUrl, e );
509                     throw new ContinuumException( "Error occurred while removing build agent " + buildAgentUrl, e );
510                 }
511             }
512         }
513     }
514 
515     public Map<String, List<PrepareBuildProjectsTask>> getProjectsInPrepareBuildQueue()
516         throws ContinuumException
517     {
518         Map<String, List<PrepareBuildProjectsTask>> map = new HashMap<String, List<PrepareBuildProjectsTask>>();
519 
520         synchronized ( overallDistributedBuildQueues )
521         {
522             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
523             {
524                 List<PrepareBuildProjectsTask> tasks = new ArrayList<PrepareBuildProjectsTask>();
525 
526                 try
527                 {
528                     if ( isAgentAvailable( buildAgentUrl ) )
529                     {
530                         log.debug( "Getting projects in prepare build queue of build agent {}", buildAgentUrl );
531 
532                         SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
533                             buildAgentUrl );
534 
535                         List<Map<String, Object>> projects = client.getProjectsInPrepareBuildQueue();
536 
537                         for ( Map<String, Object> context : projects )
538                         {
539                             tasks.add( getPrepareBuildProjectsTask( context ) );
540                         }
541 
542                         map.put( buildAgentUrl, tasks );
543                     }
544                     else
545                     {
546                         log.debug( "Unable to get projects in prepare build queue. Build agent {} not available",
547                                    buildAgentUrl );
548                     }
549                 }
550                 catch ( MalformedURLException e )
551                 {
552                     throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
553                 }
554                 catch ( Exception e )
555                 {
556                     throw new ContinuumException( "Error while retrieving projects in prepare build queue", e );
557                 }
558             }
559         }
560 
561         // call reload in case we disable a build agent
562         reload();
563 
564         return map;
565     }
566 
567     public Map<String, PrepareBuildProjectsTask> getProjectsCurrentlyPreparingBuild()
568         throws ContinuumException
569     {
570         Map<String, PrepareBuildProjectsTask> map = new HashMap<String, PrepareBuildProjectsTask>();
571 
572         synchronized ( overallDistributedBuildQueues )
573         {
574             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
575             {
576                 try
577                 {
578                     if ( isAgentAvailable( buildAgentUrl ) )
579                     {
580                         log.debug( "Getting project currently preparing build in build agent {}", buildAgentUrl );
581 
582                         SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
583                             buildAgentUrl );
584                         Map<String, Object> project = client.getProjectCurrentlyPreparingBuild();
585 
586                         if ( !project.isEmpty() )
587                         {
588                             map.put( buildAgentUrl, getPrepareBuildProjectsTask( project ) );
589                         }
590                     }
591                     else
592                     {
593                         log.debug( "Unable to get projects currently preparing build. Build agent {} is not available",
594                                    buildAgentUrl );
595                     }
596                 }
597                 catch ( MalformedURLException e )
598                 {
599                     throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
600                 }
601                 catch ( Exception e )
602                 {
603                     throw new ContinuumException(
604                         "Error retrieving projects currently preparing build in " + buildAgentUrl, e );
605                 }
606             }
607         }
608 
609         // call reload in case we disable a build agent
610         reload();
611 
612         return map;
613     }
614 
615     public Map<String, BuildProjectTask> getProjectsCurrentlyBuilding()
616         throws ContinuumException
617     {
618         Map<String, BuildProjectTask> map = new HashMap<String, BuildProjectTask>();
619 
620         synchronized ( overallDistributedBuildQueues )
621         {
622             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
623             {
624                 try
625                 {
626                     if ( isAgentAvailable( buildAgentUrl ) )
627                     {
628                         log.debug( "Getting projects currently building in build agent {}", buildAgentUrl );
629 
630                         SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
631                             buildAgentUrl );
632                         Map<String, Object> project = client.getProjectCurrentlyBuilding();
633 
634                         if ( !project.isEmpty() )
635                         {
636                             map.put( buildAgentUrl, getBuildProjectTask( project ) );
637                         }
638                     }
639                     else
640                     {
641                         log.debug( "Unable to get projects currently building. Build agent {} is not available",
642                                    buildAgentUrl );
643                     }
644                 }
645                 catch ( MalformedURLException e )
646                 {
647                     throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
648                 }
649                 catch ( Exception e )
650                 {
651                     throw new ContinuumException( "Error retrieving projects currently building in " + buildAgentUrl,
652                                                   e );
653                 }
654             }
655         }
656 
657         // call reload in case we disable a build agent
658         reload();
659 
660         return map;
661     }
662 
663     public Map<String, List<BuildProjectTask>> getProjectsInBuildQueue()
664         throws ContinuumException
665     {
666         Map<String, List<BuildProjectTask>> map = new HashMap<String, List<BuildProjectTask>>();
667 
668         synchronized ( overallDistributedBuildQueues )
669         {
670             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
671             {
672                 List<BuildProjectTask> tasks = new ArrayList<BuildProjectTask>();
673 
674                 try
675                 {
676                     if ( isAgentAvailable( buildAgentUrl ) )
677                     {
678                         log.debug( "Getting projects in build queue in build agent {}", buildAgentUrl );
679 
680                         SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
681                             buildAgentUrl );
682                         List<Map<String, Object>> projects = client.getProjectsInBuildQueue();
683 
684                         for ( Map<String, Object> context : projects )
685                         {
686                             tasks.add( getBuildProjectTask( context ) );
687                         }
688 
689                         map.put( buildAgentUrl, tasks );
690                     }
691                     else
692                     {
693                         log.debug( "Unable to get projects in build queue. Build agent {} is not available",
694                                    buildAgentUrl );
695                     }
696                 }
697                 catch ( MalformedURLException e )
698                 {
699                     throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
700                 }
701                 catch ( Exception e )
702                 {
703                     throw new ContinuumException( "Error while retrieving projects in build queue", e );
704                 }
705             }
706         }
707 
708         // call reload in case we disable a build agent
709         reload();
710 
711         return map;
712     }
713 
714     public boolean isBuildAgentBusy( String buildAgentUrl )
715     {
716         synchronized ( overallDistributedBuildQueues )
717         {
718             OverallDistributedBuildQueue overallDistributedBuildQueue = overallDistributedBuildQueues.get(
719                 buildAgentUrl );
720 
721             if ( overallDistributedBuildQueue != null &&
722                 overallDistributedBuildQueue.getDistributedBuildTaskQueueExecutor().getCurrentTask() != null )
723             {
724                 log.debug( "build agent '" + buildAgentUrl + "' is busy" );
725                 return true;
726             }
727 
728             log.debug( "build agent '" + buildAgentUrl + "' is not busy" );
729             return false;
730         }
731     }
732 
733     public void cancelDistributedBuild( String buildAgentUrl )
734         throws ContinuumException
735     {
736         try
737         {
738             if ( isAgentAvailable( buildAgentUrl ) )
739             {
740                 log.debug( "Cancelling build in build agent {}", buildAgentUrl );
741 
742                 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
743                     buildAgentUrl );
744 
745                 client.cancelBuild();
746             }
747             else
748             {
749                 log.debug( "Unable to cancel build, build agent {} is not available", buildAgentUrl );
750             }
751 
752             // call reload in case we disable the build agent
753             reload();
754         }
755         catch ( MalformedURLException e )
756         {
757             log.error( "Error cancelling build in build agent: Invalid build agent url " + buildAgentUrl );
758             throw new ContinuumException(
759                 "Error cancelling build in build agent: Invalid build agent url " + buildAgentUrl );
760         }
761         catch ( Exception e )
762         {
763             log.error( "Error occurred while cancelling build in build agent " + buildAgentUrl, e );
764             throw new ContinuumException( "Error occurred while cancelling build in build agent " + buildAgentUrl, e );
765         }
766     }
767 
768     public void cancelGroupBuild( int projectGroupId )
769         throws ContinuumException
770     {
771         log.debug( "Cancelling all builds of project group {}", projectGroupId );
772 
773         List<ProjectRunSummary> runsToDelete = new ArrayList<ProjectRunSummary>();
774 
775         synchronized ( currentRuns )
776         {
777             for ( ProjectRunSummary run : currentRuns )
778             {
779                 if ( run.getProjectGroupId() == projectGroupId )
780                 {
781                     cancelCurrentRun( run, runsToDelete );
782                 }
783             }
784 
785             if ( runsToDelete.size() > 0 )
786             {
787                 currentRuns.removeAll( runsToDelete );
788             }
789         }
790     }
791 
792     public void cancelBuild( int projectId )
793         throws ContinuumException
794     {
795         log.debug( "Cancelling all builds of project {}", projectId );
796 
797         List<ProjectRunSummary> runsToDelete = new ArrayList<ProjectRunSummary>();
798 
799         synchronized ( currentRuns )
800         {
801             for ( ProjectRunSummary run : currentRuns )
802             {
803                 if ( run.getProjectId() == projectId )
804                 {
805                     cancelCurrentRun( run, runsToDelete );
806                 }
807             }
808 
809             if ( runsToDelete.size() > 0 )
810             {
811                 currentRuns.removeAll( runsToDelete );
812             }
813         }
814     }
815 
816     private void cancelCurrentRun( ProjectRunSummary run, List<ProjectRunSummary> runsToDelete )
817         throws ContinuumException
818     {
819         int projectId = run.getProjectId();
820         int buildDefinitionId = run.getBuildDefinitionId();
821         String buildAgentUrl = run.getBuildAgentUrl();
822 
823         // try to remove from any queue first
824         removeFromPrepareBuildQueue( buildAgentUrl, run.getProjectGroupId(), run.getProjectScmRootId() );
825         removeFromBuildQueue( buildAgentUrl, projectId, buildDefinitionId );
826 
827         if ( isProjectCurrentlyPreparingBuild( projectId, buildDefinitionId ) )
828         {
829             log.debug(
830                 "Unable to cancel build of projectId={}, buildDefinitionId={} in build agent{}. Project is currently doing scm update." );
831             return;
832         }
833         else if ( isProjectCurrentlyBuilding( projectId, buildDefinitionId ) )
834         {
835             log.debug( "Cancel build of projectId={}, buildDefinitionId={} in build agent {}",
836                        new Object[]{projectId, buildDefinitionId, buildAgentUrl} );
837             cancelDistributedBuild( buildAgentUrl );
838             runsToDelete.add( run );
839         }
840         else
841         {
842             try
843             {
844                 ProjectScmRoot scmRoot = projectScmRootDao.getProjectScmRoot( run.getProjectScmRootId() );
845 
846                 if ( scmRoot != null && scmRoot.getState() == ContinuumProjectState.UPDATING )
847                 {
848                     // no longer updating, but state was not updated.
849                     scmRoot.setState( ContinuumProjectState.ERROR );
850                     scmRoot.setError(
851                         "Problem encountered while returning scm update result to master by build agent '" +
852                             buildAgentUrl + "'. \n" +
853                             "Make sure build agent is configured properly. Check the logs for more information." );
854                     projectScmRootDao.updateProjectScmRoot( scmRoot );
855 
856                     log.debug(
857                         "projectId={}, buildDefinitionId={} is not updating anymore. Problem encountered while return scm update result by build agent {}. Stopping the build.",
858                         new Object[]{projectId, buildDefinitionId, buildAgentUrl} );
859                     runsToDelete.add( run );
860                 }
861                 else if ( scmRoot != null && scmRoot.getState() == ContinuumProjectState.ERROR )
862                 {
863                     log.debug(
864                         "projectId={}, buildDefinitionId={} is not updating anymore. Problem encountered while return scm update result by build agent {}. Stopping the build.",
865                         new Object[]{projectId, buildDefinitionId, buildAgentUrl} );
866                     runsToDelete.add( run );
867                 }
868                 else
869                 {
870                     Project project = projectDao.getProject( projectId );
871                     BuildDefinition buildDefinition = buildDefinitionDao.getBuildDefinition( buildDefinitionId );
872 
873                     // no longer building, but state was not updated
874                     BuildResult buildResult = new BuildResult();
875                     buildResult.setBuildDefinition( buildDefinition );
876                     buildResult.setBuildUrl( run.getBuildAgentUrl() );
877                     buildResult.setTrigger( run.getTrigger() );
878                     buildResult.setUsername( run.getTriggeredBy() );
879                     buildResult.setState( ContinuumProjectState.ERROR );
880                     buildResult.setSuccess( false );
881                     buildResult.setStartTime( new Date().getTime() );
882                     buildResult.setEndTime( new Date().getTime() );
883                     buildResult.setExitCode( 1 );
884                     buildResult.setError(
885                         "Problem encountered while returning build result to master by build agent '" + buildAgentUrl +
886                             "'. \n" +
887                             "Make sure build agent is configured properly. Check the logs for more information." );
888                     buildResultDao.addBuildResult( project, buildResult );
889 
890                     project.setState( ContinuumProjectState.ERROR );
891                     project.setLatestBuildId( buildResult.getId() );
892                     projectDao.updateProject( project );
893 
894                     log.debug(
895                         "projectId={}, buildDefinitionId={} is not building anymore. Problem encountered while return build result by build agent {}. Stopping the build.",
896                         new Object[]{projectId, buildDefinitionId, buildAgentUrl} );
897 
898                     // create a build result
899                     runsToDelete.add( run );
900                 }
901             }
902             catch ( Exception e )
903             {
904                 log.error( "Unable to end build for projectId={}, buildDefinitionId={} : {}",
905                            new Object[]{projectId, buildDefinitionId, e.getMessage()} );
906             }
907         }
908     }
909 
910     public Map<String, Object> getBuildResult( int projectId )
911         throws ContinuumException
912     {
913         Map<String, Object> map = new HashMap<String, Object>();
914 
915         String buildAgentUrl = getBuildAgent( projectId );
916 
917         if ( buildAgentUrl == null )
918         {
919             log.debug( "Unable to determine the build agent where project is building" );
920             return null;
921         }
922 
923         try
924         {
925             if ( isAgentAvailable( buildAgentUrl ) )
926             {
927                 log.debug( "Getting build result of project in build agent {}", buildAgentUrl );
928                 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
929                     buildAgentUrl );
930 
931                 Map<String, Object> result = client.getBuildResult( projectId );
932 
933                 if ( result != null )
934                 {
935                     int buildDefinitionId = ContinuumBuildConstant.getBuildDefinitionId( result );
936 
937                     Project project = projectDao.getProjectWithAllDetails( projectId );
938                     BuildDefinition buildDefinition = buildDefinitionDao.getBuildDefinition( buildDefinitionId );
939 
940                     BuildResult oldBuildResult = buildResultDao.getLatestBuildResultForBuildDefinition( projectId,
941                                                                                                         buildDefinitionId );
942 
943                     BuildResult buildResult = distributedBuildUtil.convertMapToBuildResult( result );
944                     buildResult.setBuildDefinition( buildDefinition );
945                     buildResult.setBuildNumber( project.getBuildNumber() + 1 );
946                     buildResult.setModifiedDependencies( distributedBuildUtil.getModifiedDependencies( oldBuildResult,
947                                                                                                        result ) );
948                     buildResult.setScmResult( distributedBuildUtil.getScmResult( result ) );
949 
950                     String buildOutput = ContinuumBuildConstant.getBuildOutput( result );
951 
952                     map.put( ContinuumBuildConstant.KEY_BUILD_RESULT, buildResult );
953                     map.put( ContinuumBuildConstant.KEY_BUILD_OUTPUT, buildOutput );
954                 }
955                 else
956                 {
957                     log.debug( "No build result returned by build agent {}", buildAgentUrl );
958                 }
959             }
960             else
961             {
962                 log.debug( "Unable to get build result of project. Build agent {} is not available", buildAgentUrl );
963             }
964         }
965         catch ( MalformedURLException e )
966         {
967             throw new ContinuumException( "Invalid build agent URL '" + buildAgentUrl + "'" );
968         }
969         catch ( Exception e )
970         {
971             throw new ContinuumException( "Error while retrieving build result for project" + projectId, e );
972         }
973 
974         // call reload in case we disable the build agent
975         reload();
976 
977         return map;
978     }
979 
980     public String getBuildAgentPlatform( String buildAgentUrl )
981         throws ContinuumException
982     {
983         try
984         {
985             String platform = "";
986             if ( isAgentAvailable( buildAgentUrl ) )
987             {
988                 log.debug( "Getting build agent {} platform", buildAgentUrl );
989 
990                 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
991                     buildAgentUrl );
992                 platform = client.getBuildAgentPlatform();
993             }
994             else
995             {
996                 log.debug( "Unable to get build agent platform. Build agent {} is not available", buildAgentUrl );
997             }
998             // call reload in case we disable the build agent
999             reload();
1000             return platform;
1001         }
1002         catch ( Exception e )
1003         {
1004             throw new ContinuumException( "Unable to get platform of build agent", e );
1005         }
1006     }
1007 
1008 
1009     public List<Installation> getAvailableInstallations( String buildAgentUrl )
1010         throws ContinuumException
1011     {
1012         List<Installation> installations = new ArrayList<Installation>();
1013 
1014         try
1015         {
1016             if ( isAgentAvailable( buildAgentUrl ) )
1017             {
1018                 log.debug( "Getting available installations in build agent {}", buildAgentUrl );
1019 
1020                 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1021                     buildAgentUrl );
1022 
1023                 List<Map<String, String>> installationsList = client.getAvailableInstallations();
1024 
1025                 for ( Map context : installationsList )
1026                 {
1027                     Installation installation = new Installation();
1028                     installation.setName( ContinuumBuildConstant.getInstallationName( context ) );
1029                     installation.setType( ContinuumBuildConstant.getInstallationType( context ) );
1030                     installation.setVarName( ContinuumBuildConstant.getInstallationVarName( context ) );
1031                     installation.setVarValue( ContinuumBuildConstant.getInstallationVarValue( context ) );
1032                     installations.add( installation );
1033                 }
1034             }
1035             else
1036             {
1037                 log.debug( "Unable to get available installations. Build agent {} is not available", buildAgentUrl );
1038             }
1039 
1040             // call reload in case we disable the build agent
1041             reload();
1042 
1043             return installations;
1044         }
1045         catch ( Exception e )
1046         {
1047             throw new ContinuumException( "Unable to get available installations of build agent", e );
1048         }
1049     }
1050 
1051     public String generateWorkingCopyContent( int projectId, String directory, String baseUrl, String imageBaseUrl )
1052         throws ContinuumException
1053     {
1054         BuildResult buildResult = buildResultDao.getLatestBuildResultForProject( projectId );
1055 
1056         if ( buildResult != null )
1057         {
1058             String buildAgentUrl = buildResult.getBuildUrl();
1059 
1060             if ( buildAgentUrl == null )
1061             {
1062                 log.debug( "Unable to determine the build agent where project last built" );
1063 
1064                 return "";
1065             }
1066 
1067             try
1068             {
1069                 if ( directory == null )
1070                 {
1071                     directory = "";
1072                 }
1073 
1074                 if ( isAgentAvailable( buildAgentUrl ) )
1075                 {
1076                     log.debug( "Generating working copy content of project in build agent {}", buildAgentUrl );
1077 
1078                     SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1079                         buildAgentUrl );
1080                     return client.generateWorkingCopyContent( projectId, directory, baseUrl, imageBaseUrl );
1081                 }
1082                 else
1083                 {
1084                     log.debug( "Unable to generate working copy content of project. Build agent {} is not available",
1085                                buildAgentUrl );
1086                 }
1087             }
1088             catch ( MalformedURLException e )
1089             {
1090                 log.error( "Invalid build agent url " + buildAgentUrl );
1091             }
1092             catch ( Exception e )
1093             {
1094                 log.error( "Error while generating working copy content from build agent " + buildAgentUrl, e );
1095             }
1096         }
1097         else
1098         {
1099             log.debug( "Unable to generate working copy content. Project hasn't been built yet." );
1100         }
1101 
1102         // call reload in case we disable the build agent
1103         reload();
1104 
1105         return "";
1106     }
1107 
1108     public Map<String, Object> getFileContent( int projectId, String directory, String filename )
1109         throws ContinuumException
1110     {
1111         BuildResult buildResult = buildResultDao.getLatestBuildResultForProject( projectId );
1112 
1113         if ( buildResult != null )
1114         {
1115             String buildAgentUrl = buildResult.getBuildUrl();
1116 
1117             if ( buildAgentUrl == null )
1118             {
1119                 log.debug( "Unable to determine build agent where project last built" );
1120                 return null;
1121             }
1122 
1123             try
1124             {
1125                 if ( isAgentAvailable( buildAgentUrl ) )
1126                 {
1127                     SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1128                         buildAgentUrl );
1129                     return client.getProjectFile( projectId, directory, filename );
1130                 }
1131             }
1132             catch ( MalformedURLException e )
1133             {
1134                 log.error( "Invalid build agent url " + buildAgentUrl );
1135             }
1136             catch ( Exception e )
1137             {
1138                 log.error( "Error while retrieving content of " + filename, e );
1139             }
1140         }
1141         else
1142         {
1143             log.debug( "Unable to get file content because project hasn't been built yet" );
1144         }
1145 
1146         // call reload in case we disable the build agent
1147         reload();
1148 
1149         return null;
1150     }
1151 
1152     public void removeFromPrepareBuildQueue( String buildAgentUrl, int projectGroupId, int scmRootId )
1153         throws ContinuumException
1154     {
1155         try
1156         {
1157             if ( isAgentAvailable( buildAgentUrl ) )
1158             {
1159                 log.info( "Removing projectGroupId {} from prepare build queue of build agent {}", projectGroupId,
1160                           buildAgentUrl );
1161 
1162                 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1163                     buildAgentUrl );
1164                 client.removeFromPrepareBuildQueue( projectGroupId, scmRootId );
1165             }
1166             else
1167             {
1168                 log.debug(
1169                     "Unable to remove projectGroupId {} from prepare build queue. Build agent {} is not available",
1170                     projectGroupId, buildAgentUrl );
1171             }
1172         }
1173         catch ( MalformedURLException e )
1174         {
1175             log.error( "Unable to remove projectGroupId=" + projectGroupId + " scmRootId=" + scmRootId +
1176                            " from prepare build queue: Invalid build agent url " + buildAgentUrl );
1177             throw new ContinuumException(
1178                 "Unable to remove projectGroupId=" + projectGroupId + " scmRootId=" + scmRootId +
1179                     " from prepare build queue: Invalid build agent url " + buildAgentUrl );
1180         }
1181         catch ( Exception e )
1182         {
1183             log.error( "Error occurred while removing projectGroupId=" + projectGroupId + " scmRootId=" + scmRootId +
1184                            " from prepare build queue of agent " + buildAgentUrl, e );
1185             throw new ContinuumException(
1186                 "Error occurred while removing projectGroupId=" + projectGroupId + " scmRootId=" +
1187                     scmRootId + " from prepare build queue of agent " + buildAgentUrl, e );
1188         }
1189 
1190         // call reload in case we disable the build agent
1191         reload();
1192     }
1193 
1194     public void removeFromBuildQueue( String buildAgentUrl, int projectId, int buildDefinitionId )
1195         throws ContinuumException
1196     {
1197         try
1198         {
1199             if ( isAgentAvailable( buildAgentUrl ) )
1200             {
1201                 log.info( "Removing projectId {} from build queue of build agent {}", projectId, buildAgentUrl );
1202                 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1203                     buildAgentUrl );
1204                 client.removeFromBuildQueue( projectId, buildDefinitionId );
1205             }
1206             else
1207             {
1208                 log.debug( "Unable to remove projectId {} from build queue. Build agent {} is not available", projectId,
1209                            buildAgentUrl );
1210             }
1211         }
1212         catch ( MalformedURLException e )
1213         {
1214             log.error( "Unable to remove project " + projectId +
1215                            " from build queue: Invalid build agent url " + buildAgentUrl );
1216             throw new ContinuumException( "Unable to remove project " + projectId +
1217                                               " from build queue: Invalid build agent url " + buildAgentUrl );
1218         }
1219         catch ( Exception e )
1220         {
1221             log.error( "Error occurred while removing project " + projectId +
1222                            " from build queue of agent " + buildAgentUrl, e );
1223             throw new ContinuumException( "Error occurred while removing project " + projectId +
1224                                               " from build queue of agent " + buildAgentUrl, e );
1225         }
1226 
1227         // call reload in case we disable the build agent
1228         reload();
1229     }
1230 
1231     public void removeFromPrepareBuildQueue( List<String> hashCodes )
1232         throws ContinuumException
1233     {
1234         synchronized ( overallDistributedBuildQueues )
1235         {
1236             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1237             {
1238                 try
1239                 {
1240                     if ( isAgentAvailable( buildAgentUrl ) )
1241                     {
1242                         log.info( "Removing project groups from prepare build queue of build agent {}", buildAgentUrl );
1243 
1244                         SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1245                             buildAgentUrl );
1246                         client.removeFromPrepareBuildQueue( hashCodes );
1247                     }
1248                     else
1249                     {
1250                         log.debug(
1251                             "Unable to remove project groups from prepare build queue. Build agent {} is not available",
1252                             buildAgentUrl );
1253                     }
1254                 }
1255                 catch ( MalformedURLException e )
1256                 {
1257                     log.error( "Error trying to remove projects from prepare build queue. Invalid build agent url: " +
1258                                    buildAgentUrl );
1259                 }
1260                 catch ( Exception e )
1261                 {
1262                     log.error( "Error trying to remove projects from prepare build queue of agent " + buildAgentUrl,
1263                                e );
1264                 }
1265             }
1266         }
1267 
1268         // call reload in case we disable a build agent
1269         reload();
1270     }
1271 
1272     public void removeFromBuildQueue( List<String> hashCodes )
1273         throws ContinuumException
1274     {
1275         synchronized ( overallDistributedBuildQueues )
1276         {
1277             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1278             {
1279                 try
1280                 {
1281                     if ( isAgentAvailable( buildAgentUrl ) )
1282                     {
1283                         log.info( "Removing projects from build queue of build agent {}", buildAgentUrl );
1284 
1285                         SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1286                             buildAgentUrl );
1287                         client.removeFromBuildQueue( hashCodes );
1288                     }
1289                     else
1290                     {
1291                         log.debug( "Unable to remove projects from build queue. Build agent {} is not available",
1292                                    buildAgentUrl );
1293                     }
1294                 }
1295                 catch ( MalformedURLException e )
1296                 {
1297                     log.error(
1298                         "Error trying to remove projects from build queue. Invalid build agent url: " + buildAgentUrl );
1299                 }
1300                 catch ( Exception e )
1301                 {
1302                     log.error( "Error trying to remove projects from build queue of agent " + buildAgentUrl, e );
1303                 }
1304             }
1305         }
1306 
1307         // call reload in case we disable a build agent
1308         reload();
1309     }
1310 
1311     public boolean isProjectInAnyPrepareBuildQueue( int projectId, int buildDefinitionId )
1312         throws ContinuumException
1313     {
1314         boolean found = false;
1315 
1316         synchronized ( overallDistributedBuildQueues )
1317         {
1318             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1319             {
1320                 try
1321                 {
1322                     if ( isAgentAvailable( buildAgentUrl ) )
1323                     {
1324                         log.debug( "Checking if project {} is in prepare build queue of build agent {}", projectId,
1325                                    buildAgentUrl );
1326 
1327                         SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1328                             buildAgentUrl );
1329 
1330                         List<Map<String, Object>> projects = client.getProjectsAndBuildDefinitionsInPrepareBuildQueue();
1331 
1332                         for ( Map<String, Object> context : projects )
1333                         {
1334                             int pid = ContinuumBuildConstant.getProjectId( context );
1335                             int buildId = ContinuumBuildConstant.getBuildDefinitionId( context );
1336 
1337                             if ( pid == projectId && ( buildId == buildDefinitionId || buildDefinitionId == -1 ) )
1338                             {
1339                                 found = true;
1340                                 break;
1341                             }
1342 
1343                         }
1344                     }
1345                     else
1346                     {
1347                         log.debug(
1348                             "Unable to check if project {} is in prepare build queue. Build agent {} is not available",
1349                             projectId, buildAgentUrl );
1350                     }
1351 
1352                     if ( found )
1353                     {
1354                         break;
1355                     }
1356                 }
1357                 catch ( MalformedURLException e )
1358                 {
1359                     throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
1360                 }
1361                 catch ( Exception e )
1362                 {
1363                     throw new ContinuumException( "Error while retrieving projects in prepare build queue", e );
1364                 }
1365             }
1366         }
1367 
1368         // call reload in case we disable a build agent
1369         reload();
1370 
1371         if ( found )
1372         {
1373             return true;
1374         }
1375         else
1376         {
1377             return false;
1378         }
1379     }
1380 
1381     public boolean isProjectInAnyBuildQueue( int projectId, int buildDefinitionId )
1382         throws ContinuumException
1383     {
1384         Map<String, List<BuildProjectTask>> map = getProjectsInBuildQueue();
1385 
1386         for ( String url : map.keySet() )
1387         {
1388             for ( BuildProjectTask task : map.get( url ) )
1389             {
1390                 if ( task.getProjectId() == projectId &&
1391                     ( buildDefinitionId == -1 || task.getBuildDefinitionId() == buildDefinitionId ) )
1392                 {
1393                     return true;
1394                 }
1395             }
1396         }
1397 
1398         return false;
1399     }
1400 
1401     public boolean isProjectCurrentlyPreparingBuild( int projectId, int buildDefinitionId )
1402         throws ContinuumException
1403     {
1404         boolean found = false;
1405 
1406         synchronized ( overallDistributedBuildQueues )
1407         {
1408             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1409             {
1410                 try
1411                 {
1412                     if ( isAgentAvailable( buildAgentUrl ) )
1413                     {
1414                         log.debug( "Checking if project {} is currently preparing build in build agent {}", projectId,
1415                                    buildAgentUrl );
1416 
1417                         SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1418                             buildAgentUrl );
1419                         List<Map<String, Object>> projects =
1420                             client.getProjectsAndBuildDefinitionsCurrentlyPreparingBuild();
1421 
1422                         for ( Map<String, Object> context : projects )
1423                         {
1424                             int pid = ContinuumBuildConstant.getProjectId( context );
1425                             int buildId = ContinuumBuildConstant.getBuildDefinitionId( context );
1426 
1427                             if ( pid == projectId && ( buildDefinitionId == -1 || buildId == buildDefinitionId ) )
1428                             {
1429                                 found = true;
1430                                 break;
1431                             }
1432                         }
1433                     }
1434                     else
1435                     {
1436                         log.debug(
1437                             "Unable to check if project {} is currently preparing build. Build agent {} is not available",
1438                             projectId, buildAgentUrl );
1439                     }
1440 
1441                     if ( found )
1442                     {
1443                         break;
1444                     }
1445                 }
1446                 catch ( MalformedURLException e )
1447                 {
1448                     throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
1449                 }
1450                 catch ( Exception e )
1451                 {
1452                     throw new ContinuumException(
1453                         "Error retrieving projects currently preparing build in " + buildAgentUrl, e );
1454                 }
1455             }
1456         }
1457 
1458         // call reload in case we disable a build agent
1459         reload();
1460 
1461         if ( found )
1462         {
1463             return true;
1464         }
1465         else
1466         {
1467             return false;
1468         }
1469     }
1470 
1471     public boolean isProjectCurrentlyBuilding( int projectId, int buildDefinitionId )
1472         throws ContinuumException
1473     {
1474         Map<String, BuildProjectTask> map = getProjectsCurrentlyBuilding();
1475 
1476         for ( String url : map.keySet() )
1477         {
1478             BuildProjectTask task = map.get( url );
1479 
1480             if ( task.getProjectId() == projectId &&
1481                 ( buildDefinitionId == -1 || task.getBuildDefinitionId() == buildDefinitionId ) )
1482             {
1483                 return true;
1484             }
1485         }
1486 
1487         return false;
1488     }
1489 
1490     private String getBuildAgent( int projectId )
1491         throws ContinuumException
1492     {
1493         String agentUrl = null;
1494 
1495         synchronized ( overallDistributedBuildQueues )
1496         {
1497             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1498             {
1499                 OverallDistributedBuildQueue overallDistributedBuildQueue = overallDistributedBuildQueues.get(
1500                     buildAgentUrl );
1501 
1502                 if ( overallDistributedBuildQueue != null )
1503                 {
1504                     try
1505                     {
1506                         if ( isAgentAvailable( buildAgentUrl ) )
1507                         {
1508                             SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1509                                 buildAgentUrl );
1510 
1511                             // TODO: should check for specific build definition and handle that in UI;
1512                             // project with different build definitions can build at the same time in different agents and
1513                             // currently, we can't handle that in the ui.
1514                             if ( client.isProjectCurrentlyBuilding( projectId, -1 ) )
1515                             {
1516                                 agentUrl = buildAgentUrl;
1517                                 break;
1518                             }
1519                         }
1520                         else
1521                         {
1522                             log.debug(
1523                                 "Unable to check if project {} is currently building. Build agent {} is not available",
1524                                 projectId, buildAgentUrl );
1525                         }
1526                     }
1527                     catch ( MalformedURLException e )
1528                     {
1529                         log.warn(
1530                             "Unable to check if project {} is currently building in agent: Invalid build agent url {}",
1531                             projectId, buildAgentUrl );
1532                     }
1533                     catch ( Exception e )
1534                     {
1535                         log.warn( "Unable to check if project {} is currently building in agent", projectId, e );
1536                     }
1537                 }
1538             }
1539         }
1540 
1541         // call reload in case we disable a build agent
1542         reload();
1543 
1544         return agentUrl;
1545     }
1546 
1547     public String getBuildAgentUrl( int projectId, int buildDefinitionId )
1548         throws ContinuumException
1549     {
1550         String agentUrl = null;
1551 
1552         synchronized ( overallDistributedBuildQueues )
1553         {
1554             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1555             {
1556                 OverallDistributedBuildQueue overallDistributedBuildQueue = overallDistributedBuildQueues.get(
1557                     buildAgentUrl );
1558 
1559                 if ( overallDistributedBuildQueue != null )
1560                 {
1561                     try
1562                     {
1563                         if ( isAgentAvailable( buildAgentUrl ) )
1564                         {
1565                             log.debug(
1566                                 "Checking if project {} with build definition {} is currently queued or processed in agent {}",
1567                                 new Object[]{projectId, buildDefinitionId, buildAgentUrl} );
1568 
1569                             SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1570                                 buildAgentUrl );
1571 
1572                             if ( client.isProjectInPrepareBuildQueue( projectId, buildDefinitionId ) ||
1573                                 client.isProjectCurrentlyPreparingBuild( projectId, buildDefinitionId ) ||
1574                                 client.isProjectInBuildQueue( projectId, buildDefinitionId ) ||
1575                                 client.isProjectCurrentlyBuilding( projectId, buildDefinitionId ) )
1576                             {
1577                                 log.debug(
1578                                     "Project {} with build definition {} is currently queued or processed in agent {}",
1579                                     new Object[]{projectId, buildDefinitionId, buildAgentUrl} );
1580                                 agentUrl = buildAgentUrl;
1581                                 break;
1582                             }
1583                         }
1584                         else
1585                         {
1586                             log.debug(
1587                                 "Unable to check if project {} is currently queued or processed in agent. Build agent {} is not available",
1588                                 projectId, buildAgentUrl );
1589                         }
1590                     }
1591                     catch ( MalformedURLException e )
1592                     {
1593                         log.warn(
1594                             "Unable to check if project {} is currently queued or processed in agent: Invalid build agent url {}",
1595                             projectId, buildAgentUrl );
1596                     }
1597                     catch ( Exception e )
1598                     {
1599                         log.warn( "Unable to check if project {} is currently queued or processed in agent", projectId,
1600                                   e );
1601                     }
1602                 }
1603             }
1604         }
1605 
1606         // call reload in case we disable a build agent
1607         reload();
1608 
1609         return agentUrl;
1610     }
1611 
1612     private void createDistributedBuildQueueForAgent( String buildAgentUrl )
1613         throws ComponentLookupException
1614     {
1615         if ( !overallDistributedBuildQueues.containsKey( buildAgentUrl ) )
1616         {
1617             OverallDistributedBuildQueue overallDistributedBuildQueue = (OverallDistributedBuildQueue) container.lookup(
1618                 OverallDistributedBuildQueue.class );
1619             overallDistributedBuildQueue.setBuildAgentUrl( buildAgentUrl );
1620             overallDistributedBuildQueue.getDistributedBuildTaskQueueExecutor().setBuildAgentUrl( buildAgentUrl );
1621 
1622             overallDistributedBuildQueues.put( buildAgentUrl, overallDistributedBuildQueue );
1623         }
1624     }
1625 
1626     private OverallDistributedBuildQueue getOverallDistributedBuildQueueByScmRoot( ProjectScmRoot scmRoot,
1627                                                                                    int projectGroupId )
1628         throws ContinuumException
1629     {
1630         int scmRootId = scmRoot.getId();
1631 
1632         synchronized ( overallDistributedBuildQueues )
1633         {
1634             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1635             {
1636                 OverallDistributedBuildQueue distributedBuildQueue = overallDistributedBuildQueues.get( buildAgentUrl );
1637 
1638                 try
1639                 {
1640                     for ( PrepareBuildProjectsTask task : distributedBuildQueue.getProjectsInQueue() )
1641                     {
1642                         if ( task.getProjectScmRootId() == scmRootId )
1643                         {
1644                             log.debug(
1645                                 "Projects in the same continuum group are building in build agent: {}. Also building project in the same agent.",
1646                                 buildAgentUrl );
1647                             return distributedBuildQueue;
1648                         }
1649                     }
1650 
1651                     Task task = distributedBuildQueue.getDistributedBuildTaskQueueExecutor().getCurrentTask();
1652                     if ( task != null && ( (PrepareBuildProjectsTask) task ).getProjectScmRootId() == scmRootId )
1653                     {
1654                         log.debug(
1655                             "Projects in the same continuum group are building in build agent: {}. Also building project in the same agent.",
1656                             buildAgentUrl );
1657                         return distributedBuildQueue;
1658                     }
1659 
1660                     if ( isAgentAvailable( buildAgentUrl ) )
1661                     {
1662                         List<Project> projects = projectDao.getProjectsInGroup( projectGroupId );
1663                         List<Integer> pIds = new ArrayList<Integer>();
1664 
1665                         for ( Project project : projects )
1666                         {
1667                             if ( project.getScmUrl().startsWith( scmRoot.getScmRootAddress() ) )
1668                             {
1669                                 pIds.add( project.getId() );
1670                             }
1671                         }
1672 
1673                         SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1674                             buildAgentUrl );
1675 
1676                         if ( client.isProjectScmRootInQueue( scmRootId, pIds ) )
1677                         {
1678                             log.debug(
1679                                 "Projects in the same continuum group are building in build agent: {}. Also building project in the same agent.",
1680                                 buildAgentUrl );
1681                             return distributedBuildQueue;
1682                         }
1683                     }
1684                     else
1685                     {
1686                         log.debug( "Build agent {} is not available. Skipping...", buildAgentUrl );
1687                     }
1688                 }
1689                 catch ( TaskQueueException e )
1690                 {
1691                     log.error( "Error occurred while retrieving distributed build queue of scmRootId=" + scmRootId, e );
1692                     throw new ContinuumException( "Error occurred while retrieving distributed build queue of scmRoot",
1693                                                   e );
1694                 }
1695                 catch ( MalformedURLException e )
1696                 {
1697                     log.error( "Error occurred while retrieving distributed build queue of scmRootId=" + scmRootId +
1698                                    ": Invalid build agent url " + buildAgentUrl );
1699                     throw new ContinuumException(
1700                         "Error occurred while retrieving distributed build queue of scmRootId=" + scmRootId +
1701                             ": Invalid build agent url " + buildAgentUrl );
1702                 }
1703                 catch ( Exception e )
1704                 {
1705                     log.error( "Error occurred while retrieving distributed build queue of scmRootId=" + scmRootId, e );
1706                     throw new ContinuumException( "Error occurred while retrieving distributed build queue of scmRoot",
1707                                                   e );
1708                 }
1709             }
1710         }
1711 
1712         return null;
1713     }
1714 
1715     private OverallDistributedBuildQueue getOverallDistributedBuildQueueByGroup( int projectGroupId,
1716                                                                                  List<ProjectScmRoot> scmRoots,
1717                                                                                  int scmRootId )
1718         throws ContinuumException
1719     {
1720         if ( scmRoots != null )
1721         {
1722             log.debug( "Checking if the project group is already building in one of the build agents" );
1723 
1724             for ( ProjectScmRoot scmRoot : scmRoots )
1725             {
1726                 if ( scmRoot.getId() == scmRootId )
1727                 {
1728                     break;
1729                 }
1730                 else if ( scmRoot.getProjectGroup().getId() == projectGroupId )
1731                 {
1732                     return getOverallDistributedBuildQueueByScmRoot( scmRoot, projectGroupId );
1733                 }
1734             }
1735         }
1736         return null;
1737     }
1738 
1739     private OverallDistributedBuildQueue getOverallDistributedBuildQueueByAgentGroup(
1740         Map<Integer, Integer> projectsAndBuildDefinitionsMap )
1741         throws ContinuumException
1742     {
1743         OverallDistributedBuildQueue whereToBeQueued = null;
1744 
1745         BuildAgentGroupConfiguration buildAgentGroup = getBuildAgentGroup( projectsAndBuildDefinitionsMap );
1746 
1747         if ( buildAgentGroup != null )
1748         {
1749             List<BuildAgentConfiguration> buildAgents = buildAgentGroup.getBuildAgents();
1750 
1751             if ( buildAgents != null && buildAgents.size() > 0 )
1752             {
1753                 List<String> buildAgentUrls = new ArrayList<String>();
1754 
1755                 for ( BuildAgentConfiguration buildAgent : buildAgents )
1756                 {
1757                     buildAgentUrls.add( buildAgent.getUrl() );
1758                 }
1759 
1760                 synchronized ( overallDistributedBuildQueues )
1761                 {
1762                     int idx = 0;
1763                     int size = 0;
1764 
1765                     for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1766                     {
1767                         if ( !buildAgentUrls.isEmpty() && buildAgentUrls.contains( buildAgentUrl ) )
1768                         {
1769                             OverallDistributedBuildQueue distributedBuildQueue = overallDistributedBuildQueues.get(
1770                                 buildAgentUrl );
1771 
1772                             if ( distributedBuildQueue != null )
1773                             {
1774                                 try
1775                                 {
1776                                     if ( isAgentAvailable( buildAgentUrl ) )
1777                                     {
1778                                         log.debug( "Build agent {} is available", buildAgentUrl );
1779 
1780                                         SlaveBuildAgentTransportService client =
1781                                             createSlaveBuildAgentTransportClientConnection( buildAgentUrl );
1782                                         int agentBuildSize = client.getBuildSizeOfAgent();
1783 
1784                                         log.debug( "Number of projects currently building in agent: {}",
1785                                                    agentBuildSize );
1786                                         if ( idx == 0 )
1787                                         {
1788                                             log.debug( "Current least busy agent: {}", buildAgentUrl );
1789                                             whereToBeQueued = distributedBuildQueue;
1790                                             size = agentBuildSize;
1791                                             idx++;
1792                                         }
1793 
1794                                         if ( agentBuildSize < size )
1795                                         {
1796                                             log.debug( "Current least busy agent: {}", buildAgentUrl );
1797                                             whereToBeQueued = distributedBuildQueue;
1798                                             size = agentBuildSize;
1799                                         }
1800                                     }
1801                                     else
1802                                     {
1803                                         log.debug( "Build agent {} is not available. Skipping...", buildAgentUrl );
1804                                     }
1805                                 }
1806                                 catch ( MalformedURLException e )
1807                                 {
1808                                     log.error(
1809                                         "Error occurred while retrieving distributed build queue: Invalid build agent url " +
1810                                             buildAgentUrl );
1811                                 }
1812                                 catch ( Exception e )
1813                                 {
1814                                     log.error( "Error occurred while retrieving distributed build queue ", e );
1815                                 }
1816                             }
1817                         }
1818                     }
1819                 }
1820             }
1821         }
1822 
1823         return whereToBeQueued;
1824     }
1825 
1826     private OverallDistributedBuildQueue getOverallDistributedBuildQueue()
1827         throws ContinuumException
1828     {
1829         OverallDistributedBuildQueue whereToBeQueued = null;
1830 
1831         synchronized ( overallDistributedBuildQueues )
1832         {
1833             if ( overallDistributedBuildQueues.isEmpty() )
1834             {
1835                 log.info( "No distributed build queues are configured for build agents" );
1836                 return null;
1837             }
1838 
1839             int idx = 0;
1840             int size = 0;
1841 
1842             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1843             {
1844                 OverallDistributedBuildQueue distributedBuildQueue = overallDistributedBuildQueues.get( buildAgentUrl );
1845 
1846                 if ( distributedBuildQueue != null )
1847                 {
1848                     try
1849                     {
1850                         if ( isAgentAvailable( buildAgentUrl ) )
1851                         {
1852                             log.debug( "Build agent {} is available", buildAgentUrl );
1853 
1854                             SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1855                                 buildAgentUrl );
1856                             int agentBuildSize = client.getBuildSizeOfAgent();
1857 
1858                             log.debug( "Number of projects currently building in agent: {}", agentBuildSize );
1859                             if ( idx == 0 )
1860                             {
1861                                 log.debug( "Current least busy agent: {}", buildAgentUrl );
1862                                 whereToBeQueued = distributedBuildQueue;
1863                                 size = agentBuildSize;
1864                                 idx++;
1865                             }
1866 
1867                             if ( agentBuildSize < size )
1868                             {
1869                                 log.debug( "Current least busy agent: {}", buildAgentUrl );
1870                                 whereToBeQueued = distributedBuildQueue;
1871                                 size = agentBuildSize;
1872                             }
1873                         }
1874                         else
1875                         {
1876                             log.debug( "Build agent {} is not available. Skipping...", buildAgentUrl );
1877                         }
1878                     }
1879                     catch ( MalformedURLException e )
1880                     {
1881                         log.error( "Error occurred while retrieving distributed build queue: invalid build agent url " +
1882                                        buildAgentUrl );
1883                     }
1884                     catch ( Exception e )
1885                     {
1886                         log.error( "Error occurred while retrieving distributed build queue", e );
1887                         throw new ContinuumException( "Error occurred while retrieving distributed build queue", e );
1888                     }
1889                 }
1890             }
1891         }
1892 
1893         return whereToBeQueued;
1894     }
1895 
1896     private BuildAgentGroupConfiguration getBuildAgentGroup( Map<Integer, Integer> projectsAndBuildDefinitions )
1897         throws ContinuumException
1898     {
1899         if ( projectsAndBuildDefinitions == null )
1900         {
1901             return null;
1902         }
1903 
1904         try
1905         {
1906             List<Project> projects = new ArrayList<Project>();
1907 
1908             for ( Integer projectId : projectsAndBuildDefinitions.keySet() )
1909             {
1910                 projects.add( projectDao.getProjectWithDependencies( projectId ) );
1911             }
1912 
1913             projects = ProjectSorter.getSortedProjects( projects, log );
1914 
1915             int buildDefinitionId = projectsAndBuildDefinitions.get( projects.get( 0 ).getId() );
1916             BuildDefinition buildDefinition = buildDefinitionDao.getBuildDefinition( buildDefinitionId );
1917 
1918             Profile profile = buildDefinition.getProfile();
1919 
1920             if ( profile != null && !StringUtils.isEmpty( profile.getBuildAgentGroup() ) )
1921             {
1922                 String groupName = profile.getBuildAgentGroup();
1923 
1924                 BuildAgentGroupConfiguration buildAgentGroup = configurationService.getBuildAgentGroup( groupName );
1925 
1926                 return buildAgentGroup;
1927             }
1928         }
1929         catch ( ContinuumStoreException e )
1930         {
1931             log.error( "Error while getting build agent group", e );
1932             throw new ContinuumException( "Error while getting build agent group", e );
1933         }
1934 
1935         log.info( "profile build agent group is null" );
1936 
1937         return null;
1938     }
1939 
1940     private PrepareBuildProjectsTask getPrepareBuildProjectsTask( Map context )
1941     {
1942         int projectGroupId = ContinuumBuildConstant.getProjectGroupId( context );
1943         int scmRootId = ContinuumBuildConstant.getScmRootId( context );
1944         String scmRootAddress = ContinuumBuildConstant.getScmRootAddress( context );
1945         BuildTrigger buildTrigger = new BuildTrigger( ContinuumBuildConstant.getTrigger( context ),
1946                                                       ContinuumBuildConstant.getUsername( context ) );
1947 
1948         return new PrepareBuildProjectsTask( null, buildTrigger, projectGroupId, null, scmRootAddress, scmRootId );
1949     }
1950 
1951     private BuildProjectTask getBuildProjectTask( Map context )
1952     {
1953         int projectId = ContinuumBuildConstant.getProjectId( context );
1954         int buildDefinitionId = ContinuumBuildConstant.getBuildDefinitionId( context );
1955         BuildTrigger buildTrigger = new BuildTrigger( ContinuumBuildConstant.getTrigger( context ),
1956                                                       ContinuumBuildConstant.getUsername( context ) );
1957         int projectGroupId = ContinuumBuildConstant.getProjectGroupId( context );
1958         String buildDefinitionLabel = ContinuumBuildConstant.getBuildDefinitionLabel( context );
1959 
1960         return new BuildProjectTask( projectId, buildDefinitionId, buildTrigger, null, buildDefinitionLabel, null,
1961                                      projectGroupId );
1962     }
1963 
1964     public boolean isAgentAvailable( String buildAgentUrl )
1965         throws ContinuumException
1966     {
1967         try
1968         {
1969             if ( pingBuildAgent( buildAgentUrl ) )
1970             {
1971                 return true;
1972             }
1973         }
1974         catch ( Exception e )
1975         {
1976             log.warn( "Disable build agent: {}; Unable to ping due to {}", buildAgentUrl, e );
1977         }
1978 
1979         // disable it
1980         disableBuildAgent( buildAgentUrl );
1981 
1982         return false;
1983     }
1984 
1985     public boolean pingBuildAgent( String buildAgentUrl )
1986         throws ContinuumException
1987     {
1988         try
1989         {
1990             SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection( buildAgentUrl );
1991 
1992             return client.ping();
1993         }
1994         catch ( MalformedURLException e )
1995         {
1996             log.warn( "Invalid build agent url {}", buildAgentUrl );
1997         }
1998         catch ( Exception e )
1999         {
2000             throw new ContinuumException( "Unable to ping build agent " + buildAgentUrl + " : " + e.getMessage() );
2001         }
2002 
2003         return false;
2004     }
2005 
2006     public List<ProjectRunSummary> getCurrentRuns()
2007     {
2008         return currentRuns;
2009     }
2010 
2011     public void removeCurrentRun( int projectId, int buildDefinitionId )
2012     {
2013         synchronized ( currentRuns )
2014         {
2015             boolean found = false;
2016             ProjectRunSummary runToDelete = null;
2017 
2018             for ( ProjectRunSummary currentRun : currentRuns )
2019             {
2020                 if ( currentRun.getProjectId() == projectId && currentRun.getBuildDefinitionId() == buildDefinitionId )
2021                 {
2022                     found = true;
2023                     runToDelete = currentRun;
2024                     break;
2025                 }
2026             }
2027 
2028             if ( found )
2029             {
2030                 currentRuns.remove( runToDelete );
2031             }
2032         }
2033     }
2034 
2035     private void createProjectRunSummaries( PrepareBuildProjectsTask task, String buildAgentUrl )
2036     {
2037         synchronized ( currentRuns )
2038         {
2039             int projectGroupId = task.getProjectGroupId();
2040             int projectScmRootId = task.getProjectScmRootId();
2041             Map<Integer, Integer> map = task.getProjectsBuildDefinitionsMap();
2042 
2043             for ( int projectId : map.keySet() )
2044             {
2045                 int buildDefinitionId = map.get( projectId );
2046 
2047                 ProjectRunSummary runToDelete = null;
2048 
2049                 // check if there is an existing current run with that project id and build definition id
2050                 for ( ProjectRunSummary currentRun : currentRuns )
2051                 {
2052                     if ( currentRun.getProjectId() == projectId &&
2053                         currentRun.getBuildDefinitionId() == buildDefinitionId )
2054                     {
2055                         runToDelete = currentRun;
2056                         break;
2057                     }
2058                 }
2059 
2060                 if ( runToDelete != null )
2061                 {
2062                     // previous run already finished, but was not removed from the list
2063                     // removed it
2064                     currentRuns.remove( runToDelete );
2065                 }
2066 
2067                 ProjectRunSummary run = new ProjectRunSummary();
2068                 run.setProjectGroupId( projectGroupId );
2069                 run.setProjectScmRootId( projectScmRootId );
2070                 run.setProjectId( projectId );
2071                 run.setBuildDefinitionId( buildDefinitionId );
2072                 run.setTriggeredBy( task.getBuildTrigger().getTriggeredBy() );
2073                 run.setTrigger( task.getBuildTrigger().getTrigger() );
2074                 run.setBuildAgentUrl( buildAgentUrl );
2075                 currentRuns.add( run );
2076             }
2077         }
2078     }
2079 
2080     private void disableBuildAgent( String buildAgentUrl )
2081         throws ContinuumException
2082     {
2083         List<BuildAgentConfiguration> agents = configurationService.getBuildAgents();
2084 
2085         for ( BuildAgentConfiguration agent : agents )
2086         {
2087             if ( agent.getUrl().equals( buildAgentUrl ) )
2088             {
2089                 agent.setEnabled( false );
2090                 configurationService.updateBuildAgent( agent );
2091 
2092                 try
2093                 {
2094                     configurationService.store();
2095 
2096                     log.debug( "Disabled build agent {}", buildAgentUrl );
2097                 }
2098                 catch ( Exception e )
2099                 {
2100                     throw new ContinuumException( "Unable to disable build agent: " + buildAgentUrl, e );
2101                 }
2102             }
2103         }
2104     }
2105 
2106     private boolean hasBuildagentGroup( Map<Integer, Integer> projectsAndBuildDefinitionsMap )
2107         throws ContinuumException
2108     {
2109         BuildAgentGroupConfiguration buildAgentGroup = getBuildAgentGroup( projectsAndBuildDefinitionsMap );
2110 
2111         return buildAgentGroup != null && buildAgentGroup.getName().length() > 0 ? true : false;
2112     }
2113 
2114     private boolean hasBuildagentInGroup( Map<Integer, Integer> projectsAndBuildDefinitionsMap )
2115         throws ContinuumException
2116     {
2117         BuildAgentGroupConfiguration buildAgentGroup = getBuildAgentGroup( projectsAndBuildDefinitionsMap );
2118 
2119         return buildAgentGroup != null && buildAgentGroup.getBuildAgents().size() > 0 ? true : false;
2120     }
2121 
2122     public SlaveBuildAgentTransportService createSlaveBuildAgentTransportClientConnection( String buildAgentUrl )
2123         throws MalformedURLException, Exception
2124     {
2125         return new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ), "",
2126                                                    configurationService.getSharedSecretPassword() );
2127     }
2128 
2129     // for unit testing
2130 
2131     public void setOverallDistributedBuildQueues(
2132         Map<String, OverallDistributedBuildQueue> overallDistributedBuildQueues )
2133     {
2134         this.overallDistributedBuildQueues = overallDistributedBuildQueues;
2135     }
2136 
2137     public void setConfigurationService( ConfigurationService configurationService )
2138     {
2139         this.configurationService = configurationService;
2140     }
2141 
2142     public void setProjectDao( ProjectDao projectDao )
2143     {
2144         this.projectDao = projectDao;
2145     }
2146 
2147     public void setBuildDefinitionDao( BuildDefinitionDao buildDefinitionDao )
2148     {
2149         this.buildDefinitionDao = buildDefinitionDao;
2150     }
2151 
2152     public void setBuildResultDao( BuildResultDao buildResultDao )
2153     {
2154         this.buildResultDao = buildResultDao;
2155     }
2156 
2157     public void setContainer( PlexusContainer container )
2158     {
2159         this.container = container;
2160     }
2161 
2162     public void setCurrentRuns( List<ProjectRunSummary> currentRuns )
2163     {
2164         this.currentRuns = currentRuns;
2165     }
2166 
2167     public void setProjectScmRootDao( ProjectScmRootDao projectScmRootDao )
2168     {
2169         this.projectScmRootDao = projectScmRootDao;
2170     }
2171 }