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 java.net.MalformedURLException;
23  import java.net.URL;
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  
30  import org.apache.continuum.builder.distributed.executor.ThreadedDistributedBuildTaskQueueExecutor;
31  import org.apache.continuum.builder.distributed.util.DistributedBuildUtil;
32  import org.apache.continuum.builder.utils.ContinuumBuildConstant;
33  import org.apache.continuum.configuration.BuildAgentConfiguration;
34  import org.apache.continuum.configuration.BuildAgentGroupConfiguration;
35  import org.apache.continuum.dao.BuildDefinitionDao;
36  import org.apache.continuum.dao.BuildResultDao;
37  import org.apache.continuum.dao.ProjectDao;
38  import org.apache.continuum.distributed.transport.slave.SlaveBuildAgentTransportClient;
39  import org.apache.continuum.taskqueue.BuildProjectTask;
40  import org.apache.continuum.taskqueue.OverallDistributedBuildQueue;
41  import org.apache.continuum.taskqueue.PrepareBuildProjectsTask;
42  import org.apache.continuum.utils.ContinuumUtils;
43  import org.apache.continuum.utils.ProjectSorter;
44  import org.apache.maven.continuum.ContinuumException;
45  import org.apache.maven.continuum.configuration.ConfigurationService;
46  import org.apache.maven.continuum.model.project.BuildDefinition;
47  import org.apache.maven.continuum.model.project.BuildResult;
48  import org.apache.maven.continuum.model.project.Project;
49  import org.apache.maven.continuum.model.system.Installation;
50  import org.apache.maven.continuum.model.system.Profile;
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  /**
69   * @author Maria Catherine Tan
70   * @plexus.component role="org.apache.continuum.builder.distributed.manager.DistributedBuildManager"
71   */
72  public class DefaultDistributedBuildManager
73      implements DistributedBuildManager, Contextualizable, Initializable
74  {
75      private static final Logger log = LoggerFactory.getLogger( DefaultDistributedBuildManager.class );
76  
77      private Map<String, OverallDistributedBuildQueue> overallDistributedBuildQueues =
78          Collections.synchronizedMap( new HashMap<String, OverallDistributedBuildQueue>() );
79  
80      /**
81       * @plexus.requirement
82       */
83      private ConfigurationService configurationService;
84  
85      /**
86       * @plexus.requirement
87       */
88      private ProjectDao projectDao;
89  
90      /**
91       * @plexus.requirement
92       */
93      private BuildDefinitionDao buildDefinitionDao;
94  
95      /**
96       * @plexus.requirement
97       */
98      private BuildResultDao buildResultDao;
99  
100     /**
101      * @plexus.requirement
102      */
103     private DistributedBuildUtil distributedBuildUtil;
104 
105     private PlexusContainer container;
106 
107     // --------------------------------
108     //  Plexus Lifecycle
109     // --------------------------------
110     public void contextualize( Context context )
111         throws ContextException
112     {
113         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
114     }
115 
116     public void initialize()
117         throws InitializationException
118     {
119         List<BuildAgentConfiguration> agents = configurationService.getBuildAgents();
120 
121         if ( agents != null )
122         {
123             synchronized( overallDistributedBuildQueues )
124             {
125                 for ( BuildAgentConfiguration agent : agents )
126                 {
127                     if ( agent.isEnabled() )
128                     {
129                         try
130                         {
131                             SlaveBuildAgentTransportClient client =
132                                 new SlaveBuildAgentTransportClient( new URL( agent.getUrl() ) );
133     
134                             if ( client.ping() )
135                             {
136                                 log.info(
137                                     "agent is enabled, create distributed build queue for build agent '" + agent.getUrl() + "'" );
138                                 createDistributedBuildQueueForAgent( agent.getUrl() );
139                             }
140                             else
141                             {
142                                 log.info( "unable to ping build agent '" + agent.getUrl() + "'" );
143                             }
144                         }
145                         catch ( MalformedURLException e )
146                         {
147                             // do not throw exception, just log it
148                             log.info( "Invalid build agent URL " + agent.getUrl() + ", not creating distributed build queue" );
149                         }
150                         catch ( ContinuumException e )
151                         {
152                             throw new InitializationException(
153                                 "Error while initializing distributed build queues", e );
154                         }
155                         catch ( Exception e )
156                         {
157                             agent.setEnabled( false );
158                             log.info( "unable to ping build agent '" + agent.getUrl() + "': " +
159                                 ContinuumUtils.throwableToString( e ) );
160                         }
161                     }
162                 }
163             }
164         }
165     }
166 
167     public void reload()
168         throws ContinuumException
169     {
170         List<BuildAgentConfiguration> agents = configurationService.getBuildAgents();
171 
172         synchronized( overallDistributedBuildQueues )
173         {
174             for ( BuildAgentConfiguration agent : agents )
175             {
176                 if ( agent.isEnabled() && !overallDistributedBuildQueues.containsKey( agent.getUrl() ) )
177                 {
178                     try
179                     {
180                         SlaveBuildAgentTransportClient client =
181                             new SlaveBuildAgentTransportClient( new URL( agent.getUrl() ) );
182     
183                         if ( client.ping() )
184                         {
185                             log.info( "agent is enabled, create distributed build queue for build agent '" + agent.getUrl() + "'" );
186                             createDistributedBuildQueueForAgent( agent.getUrl() );
187                         }
188                         else
189                         {
190                             log.info( "unable to ping build agent '" + agent.getUrl() + "'" );
191                         }
192                     }
193                     catch ( MalformedURLException e )
194                     {
195                         // do not throw exception, just log it
196                         log.info( "Invalid build agent URL " + agent.getUrl() + ", not creating distributed build queue" );
197                     }
198                     catch ( Exception e )
199                     {
200                         agent.setEnabled( false );
201                         log.info( "unable to ping build agent '" + agent.getUrl() + "': " +
202                             ContinuumUtils.throwableToString( e ) );
203                     }
204                 }
205                 else if ( !agent.isEnabled() && overallDistributedBuildQueues.containsKey( agent.getUrl() ) )
206                 {
207                     log.info( "agent is disabled, remove distributed build queue for build agent '" + agent.getUrl() + "'" );
208                     removeDistributedBuildQueueOfAgent( agent.getUrl() );
209                 }
210             }
211         }
212     }
213 
214     public void prepareBuildProjects( Map<Integer, Integer>projectsBuildDefinitionsMap, int trigger, int projectGroupId, 
215                                       String projectGroupName, String scmRootAddress, int scmRootId )
216         throws ContinuumException
217     {
218         PrepareBuildProjectsTask task = new PrepareBuildProjectsTask( projectsBuildDefinitionsMap, trigger,
219                                                                       projectGroupId, projectGroupName, 
220                                                                       scmRootAddress, scmRootId );
221 
222         OverallDistributedBuildQueue overallDistributedBuildQueue = getOverallDistributedBuildQueueByGroup( projectGroupId );
223 
224         if ( overallDistributedBuildQueue == null )
225         {
226             // get overall distributed build queue from build agent group
227             overallDistributedBuildQueue = getOverallDistributedBuildQueueByAgentGroup( projectsBuildDefinitionsMap );
228         }
229         
230         if ( overallDistributedBuildQueue == null )
231         {
232             overallDistributedBuildQueue = getOverallDistributedBuildQueue();
233         }
234 
235         if ( overallDistributedBuildQueue != null )
236         {
237             try
238             {
239                 overallDistributedBuildQueue.addToDistributedBuildQueue( task );
240             }
241             catch ( TaskQueueException e )
242             {
243                 log.error( "Error while enqueuing prepare build task", e );
244                 throw new ContinuumException( "Error occurred while enqueuing prepare build task", e );
245             }
246         }
247         else
248         {
249             log.warn( "No build agent configured. Not building projects." );
250         }
251     }
252 
253     public void removeDistributedBuildQueueOfAgent( String buildAgentUrl )
254         throws ContinuumException
255     {
256         if ( overallDistributedBuildQueues.containsKey( buildAgentUrl ) )
257         {
258             List<PrepareBuildProjectsTask> tasks = null;
259 
260             synchronized( overallDistributedBuildQueues )
261             {
262                 OverallDistributedBuildQueue overallDistributedBuildQueue = overallDistributedBuildQueues.get( buildAgentUrl );
263 
264                 try
265                 {
266                     if ( overallDistributedBuildQueue.getDistributedBuildTaskQueueExecutor().getCurrentTask() != null )
267                     {
268                         log.error( "Unable to remove build agent because it is currently being used" );
269                         throw new ContinuumException( "Unable to remove build agent because it is currently being used" );
270                     }
271 
272                     tasks = overallDistributedBuildQueue.getProjectsInQueue();
273 
274                     overallDistributedBuildQueue.getDistributedBuildQueue().removeAll( tasks );
275 
276                     ( (ThreadedDistributedBuildTaskQueueExecutor) overallDistributedBuildQueue.getDistributedBuildTaskQueueExecutor() ).stop();
277 
278                     container.release( overallDistributedBuildQueue );
279 
280                     log.info( "remove distributed build queue for build agent '" + buildAgentUrl + "'" );
281                 }
282                 catch ( TaskQueueException e )
283                 {
284                     log.error( "Error occurred while removing build agent " + buildAgentUrl, e );
285                     throw new ContinuumException( "Error occurred while removing build agent " + buildAgentUrl, e );
286                 }
287                 catch ( ComponentLifecycleException e )
288                 {
289                     log.error( "Error occurred while removing build agent " + buildAgentUrl, e );
290                     throw new ContinuumException( "Error occurred while removing build agent " + buildAgentUrl, e );
291                 }
292                 catch ( StoppingException e )
293                 {
294                     log.error( "Error occurred while removing build agent " + buildAgentUrl, e );
295                     throw new ContinuumException( "Error occurred while removing build agent " + buildAgentUrl, e );
296                 }
297             }
298         }
299     }
300 
301     public Map<String, List<PrepareBuildProjectsTask>> getProjectsInPrepareBuildQueue()
302         throws ContinuumException
303     {
304         Map<String, List<PrepareBuildProjectsTask>> map = new HashMap<String, List<PrepareBuildProjectsTask>>();
305 
306         synchronized( overallDistributedBuildQueues )
307         {
308             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
309             {
310                 List<PrepareBuildProjectsTask> tasks = new ArrayList<PrepareBuildProjectsTask>();
311 
312                 try
313                 {
314                     SlaveBuildAgentTransportClient client =
315                         new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
316                     List<Map<String, Object>> projects = client.getProjectsInPrepareBuildQueue();
317 
318                     for ( Map<String, Object> context : projects )
319                     {
320                         tasks.add( getPrepareBuildProjectsTask( context ) );
321                     }
322 
323                     map.put( buildAgentUrl, tasks );
324                 }
325                 catch ( MalformedURLException e )
326                 {
327                     throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl ); 
328                 }
329                 catch ( Exception e )
330                 {
331                     throw new ContinuumException( "Error while retrieving projects in prepare build queue", e );
332                 }
333             }
334         }
335 
336         return map;
337     }
338 
339     public Map<String, PrepareBuildProjectsTask> getProjectsCurrentlyPreparingBuild()
340         throws ContinuumException
341     {
342         Map<String, PrepareBuildProjectsTask> map = new HashMap<String, PrepareBuildProjectsTask>();
343 
344         synchronized( overallDistributedBuildQueues )
345         {
346             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
347             {
348                 try
349                 {
350                     SlaveBuildAgentTransportClient client =
351                         new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
352                     Map<String, Object> project = client.getProjectCurrentlyPreparingBuild();
353 
354                     if ( !project.isEmpty() )
355                     {
356                         map.put( buildAgentUrl, getPrepareBuildProjectsTask( project ) );
357                     }
358                 }
359                 catch ( MalformedURLException e )
360                 {
361                     throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
362                 }
363                 catch ( Exception e )
364                 {
365                     throw new ContinuumException( "Error retrieving projects currently preparing build in " + buildAgentUrl, e );
366                 }
367             }
368         }
369         return map;
370     }
371  
372     public Map<String, BuildProjectTask> getProjectsCurrentlyBuilding()
373         throws ContinuumException
374     {
375         Map<String, BuildProjectTask> map = new HashMap<String, BuildProjectTask>();
376 
377         synchronized( overallDistributedBuildQueues )
378         {
379             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
380             {
381                 try
382                 {
383                     SlaveBuildAgentTransportClient client =
384                         new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
385                     Map<String, Object> project = client.getProjectCurrentlyBuilding();
386 
387                     if ( !project.isEmpty() )
388                     {
389                         map.put( buildAgentUrl, getBuildProjectTask( project ) );
390                     }
391                 }
392                 catch ( MalformedURLException e )
393                 {
394                     throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
395                 }
396                 catch ( Exception e )
397                 {
398                     throw new ContinuumException( "Error retrieving projects currently building in " + buildAgentUrl, e );
399                 }
400             }
401         }
402 
403         return map;
404     }
405 
406     public Map<String, List<BuildProjectTask>> getProjectsInBuildQueue()
407         throws ContinuumException
408     {
409         Map<String, List<BuildProjectTask>> map = new HashMap<String, List<BuildProjectTask>>();
410 
411         synchronized( overallDistributedBuildQueues )
412         {
413             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
414             {
415                 List<BuildProjectTask> tasks = new ArrayList<BuildProjectTask>();
416 
417                 try
418                 {
419                     SlaveBuildAgentTransportClient client =
420                         new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
421                     List<Map<String, Object>> projects = client.getProjectsInBuildQueue();
422 
423                     for ( Map<String, Object> context : projects )
424                     {
425                         tasks.add( getBuildProjectTask( context ) );
426                     }
427 
428                     map.put( buildAgentUrl, tasks );
429                 }
430                 catch ( MalformedURLException e )
431                 {
432                     throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl ); 
433                 }
434                 catch ( Exception e )
435                 {
436                     throw new ContinuumException( "Error while retrieving projects in build queue", e );
437                 }
438             }
439         }
440         return map;
441     }
442 
443     public boolean isBuildAgentBusy( String buildAgentUrl )
444     {
445         synchronized ( overallDistributedBuildQueues )
446         {
447             OverallDistributedBuildQueue overallDistributedBuildQueue = overallDistributedBuildQueues.get( buildAgentUrl );
448 
449             if ( overallDistributedBuildQueue != null && 
450                  overallDistributedBuildQueue.getDistributedBuildTaskQueueExecutor().getCurrentTask() != null )
451             {
452                 log.info( "build agent '" + buildAgentUrl + "' is busy" );
453                 return true;
454             }
455 
456             log.info( "build agent '" + buildAgentUrl + "' is not busy" );
457             return false;
458         }
459     }
460 
461     public void cancelDistributedBuild( String buildAgentUrl )
462         throws ContinuumException
463     {
464         try
465         {
466             SlaveBuildAgentTransportClient client = new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
467 
468             client.cancelBuild();
469         }
470         catch ( MalformedURLException e )
471         {
472             log.error( "Error cancelling build in build agent: Invalid build agent url " + buildAgentUrl );
473             throw new ContinuumException( "Error cancelling build in build agent: Invalid build agent url " + buildAgentUrl );
474         }
475         catch ( Exception e )
476         {
477             log.error( "Error occurred while cancelling build in build agent " + buildAgentUrl, e );
478             throw new ContinuumException( "Error occurred while cancelling build in build agent " + buildAgentUrl, e );
479         }
480     }
481 
482     public Map<String, Object> getBuildResult( int projectId )
483         throws ContinuumException
484     {
485         Map<String, Object> map = new HashMap<String, Object>();
486     
487         String buildAgentUrl = getBuildAgent( projectId );
488     
489         if ( buildAgentUrl == null )
490         {
491             return null;
492         }
493     
494         try
495         {
496             SlaveBuildAgentTransportClient client = new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
497     
498             Map<String, Object> result = client.getBuildResult( projectId );
499     
500             if ( result != null )
501             {
502                 int buildDefinitionId = ContinuumBuildConstant.getBuildDefinitionId( result );
503     
504                 Project project = projectDao.getProjectWithAllDetails( projectId );
505                 BuildDefinition buildDefinition = buildDefinitionDao.getBuildDefinition( buildDefinitionId );
506     
507                 BuildResult oldBuildResult =
508                     buildResultDao.getLatestBuildResultForBuildDefinition( projectId, buildDefinitionId );
509     
510                 BuildResult buildResult = distributedBuildUtil.convertMapToBuildResult( result );
511                 buildResult.setBuildDefinition( buildDefinition );
512                 buildResult.setBuildNumber( project.getBuildNumber() + 1 );
513                 buildResult.setModifiedDependencies( distributedBuildUtil.getModifiedDependencies( oldBuildResult, result ) );
514                 buildResult.setScmResult( distributedBuildUtil.getScmResult( result ) );
515     
516                 String buildOutput = ContinuumBuildConstant.getBuildOutput( result );
517     
518                 map.put( ContinuumBuildConstant.KEY_BUILD_RESULT, buildResult );
519                 map.put( ContinuumBuildConstant.KEY_BUILD_OUTPUT, buildOutput );
520             }
521         }
522         catch ( MalformedURLException e )
523         {
524             throw new ContinuumException( "Invalid build agent URL '" + buildAgentUrl + "'" );
525         }
526         catch ( Exception e )
527         {
528             throw new ContinuumException( "Error while retrieving build result for project" + projectId, e );
529         }
530     
531         return map;
532     }
533 
534     public List<Installation> getAvailableInstallations( String buildAgentUrl )
535         throws ContinuumException
536     {
537         List<Installation> installations = new ArrayList<Installation>();
538     
539         try
540         {
541             SlaveBuildAgentTransportClient client = new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
542     
543             List<Map<String, String>> installationsList = client.getAvailableInstallations();
544     
545             for ( Map context : installationsList )
546             {
547                 Installation installation = new Installation();
548                 installation.setName( ContinuumBuildConstant.getInstallationName( context ) );
549                 installation.setType( ContinuumBuildConstant.getInstallationType( context ) );
550                 installation.setVarName( ContinuumBuildConstant.getInstallationVarName( context ) );
551                 installation.setVarValue( ContinuumBuildConstant.getInstallationVarValue( context ) );
552                 installations.add( installation );
553             }
554     
555             return installations;
556         }
557         catch ( Exception e )
558         {
559             throw new ContinuumException( "Unable to get available installations of build agent", e );
560         }
561     }
562 
563     public String generateWorkingCopyContent( int projectId, String directory, String baseUrl, String imageBaseUrl )
564         throws ContinuumException
565     {
566         BuildResult buildResult = buildResultDao.getLatestBuildResultForProject( projectId );
567     
568         if ( buildResult != null )
569         {
570             String buildAgentUrl = buildResult.getBuildUrl();
571     
572             if ( buildAgentUrl == null )
573             {
574                 return "";
575             }
576     
577             try
578             {
579                 if ( directory == null )
580                 {
581                     directory = "";
582                 }
583     
584                 SlaveBuildAgentTransportClient client = new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
585                 return client.generateWorkingCopyContent( projectId, directory, baseUrl, imageBaseUrl );
586             }
587             catch ( MalformedURLException e )
588             {
589                 log.error( "Invalid build agent url " + buildAgentUrl );
590             }
591             catch ( Exception e )
592             {
593                 log.error( "Error while generating working copy content from build agent " + buildAgentUrl, e );
594             }
595         }
596         return "";
597     }
598     
599     public String getFileContent( int projectId, String directory, String filename )
600         throws ContinuumException
601     {
602         BuildResult buildResult = buildResultDao.getLatestBuildResultForProject( projectId );
603     
604         if ( buildResult != null )
605         {
606             String buildAgentUrl = buildResult.getBuildUrl();
607     
608             if ( buildAgentUrl == null )
609             {
610                 return "";
611             }
612     
613             try
614             {
615                 SlaveBuildAgentTransportClient client = new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
616                 return client.getProjectFileContent( projectId, directory, filename );
617             }
618             catch ( MalformedURLException e )
619             {
620                 log.error( "Invalid build agent url " + buildAgentUrl );
621             }
622             catch ( Exception e )
623             {
624                 log.error( "Error while retrieving content of " + filename, e );
625             }
626         }
627         return "";
628     }
629 
630     public void removeFromPrepareBuildQueue( String buildAgentUrl, int projectGroupId, int scmRootId )
631         throws ContinuumException
632     {
633         try
634         {
635             SlaveBuildAgentTransportClient client = new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
636             client.removeFromPrepareBuildQueue( projectGroupId, scmRootId );
637         }
638         catch ( MalformedURLException e )
639         {
640             log.error( "Unable to remove projectGroupId=" + projectGroupId + " scmRootId=" + scmRootId + 
641                        " from prepare build queue: Invalid build agent url " + buildAgentUrl );
642             throw new ContinuumException( "Unable to remove projectGroupId=" + projectGroupId + " scmRootId=" + scmRootId + 
643                                           " from prepare build queue: Invalid build agent url " + buildAgentUrl );
644         }
645         catch ( Exception e )
646         {
647             log.error( "Error occurred while removing projectGroupId=" + projectGroupId + " scmRootId=" + scmRootId + 
648                        " from prepare build queue of agent " + buildAgentUrl, e );
649             throw new ContinuumException( "Error occurred while removing projectGroupId=" + projectGroupId + " scmRootId=" +
650                                           scmRootId + " from prepare build queue of agent " + buildAgentUrl, e );
651         }
652     }
653 
654     public void removeFromBuildQueue( String buildAgentUrl, int projectId, int buildDefinitionId )
655         throws ContinuumException
656     {
657         try
658         {
659             SlaveBuildAgentTransportClient client = new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
660             client.removeFromBuildQueue( projectId, buildDefinitionId );
661         }
662         catch ( MalformedURLException e )
663         {
664             log.error( "Unable to remove project " + projectId + 
665                        " from build queue: Invalid build agent url " + buildAgentUrl );
666             throw new ContinuumException( "Unable to remove project " + projectId + 
667                                           " from build queue: Invalid build agent url " + buildAgentUrl );
668         }
669         catch ( Exception e )
670         {
671             log.error( "Error occurred while removing project " + projectId +
672                        " from build queue of agent " + buildAgentUrl, e );
673             throw new ContinuumException( "Error occurred while removing project " + projectId + 
674                                           " from build queue of agent " + buildAgentUrl, e );
675         }
676     }
677 
678     public void removeFromPrepareBuildQueue( List<String> hashCodes )
679         throws ContinuumException
680     {
681         synchronized ( overallDistributedBuildQueues )
682         {
683             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
684             {
685                 try
686                 {
687                     SlaveBuildAgentTransportClient client = new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
688                     client.removeFromPrepareBuildQueue( hashCodes );
689                 }
690                 catch ( MalformedURLException e )
691                 {
692                     log.error( "Error trying to remove projects from prepare build queue. Invalid build agent url: " + buildAgentUrl );
693                 }
694                 catch ( Exception e )
695                 {
696                     log.error( "Error trying to remove projects from prepare build queue of agent " + buildAgentUrl, e );
697                 }
698             }
699         }
700     }
701 
702     public void removeFromBuildQueue( List<String> hashCodes )
703         throws ContinuumException
704     {
705         synchronized ( overallDistributedBuildQueues )
706         {
707             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
708             {
709                 try
710                 {
711                     SlaveBuildAgentTransportClient client = new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
712                     client.removeFromBuildQueue( hashCodes );
713                 }
714                 catch ( MalformedURLException e )
715                 {
716                     log.error( "Error trying to remove projects from build queue. Invalid build agent url: " + buildAgentUrl );
717                 }
718                 catch ( Exception e )
719                 {
720                     log.error( "Error trying to remove projects from build queue of agent " + buildAgentUrl, e );
721                 }
722             }
723         }
724     }
725 
726     private String getBuildAgent( int projectId )
727         throws ContinuumException
728     {
729         synchronized( overallDistributedBuildQueues )
730         {
731             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
732             {
733                 OverallDistributedBuildQueue overallDistributedBuildQueue = 
734                     overallDistributedBuildQueues.get( buildAgentUrl );
735     
736                 if ( overallDistributedBuildQueue != null )
737                 {
738                     try
739                     {
740                         SlaveBuildAgentTransportClient client = 
741                             new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
742                         
743                         if ( client.isProjectCurrentlyBuilding( projectId ) )
744                         {
745                             return buildAgentUrl;
746                         }
747                     }
748                     catch ( MalformedURLException e )
749                     {
750                         log.warn( "Unable to check if project " + projectId + " is currently building in agent: Invalid build agent url" + buildAgentUrl );
751                     }
752                     catch ( Exception e )
753                     {
754                         log.warn( "Unable to check if project " + projectId + " is currently building in agent", e );
755                     }
756                 }
757             }
758         }
759     
760         return null;
761     }
762 
763     private void createDistributedBuildQueueForAgent( String buildAgentUrl )
764         throws ComponentLookupException
765     {
766         if ( !overallDistributedBuildQueues.containsKey( buildAgentUrl ) )
767         {
768             OverallDistributedBuildQueue overallDistributedBuildQueue =
769                 (OverallDistributedBuildQueue) container.lookup( OverallDistributedBuildQueue.class );
770             overallDistributedBuildQueue.setBuildAgentUrl( buildAgentUrl );
771             overallDistributedBuildQueue.getDistributedBuildTaskQueueExecutor().setBuildAgentUrl( buildAgentUrl );
772 
773             overallDistributedBuildQueues.put( buildAgentUrl, overallDistributedBuildQueue );
774         }
775     }
776 
777     private OverallDistributedBuildQueue getOverallDistributedBuildQueueByGroupAndScmRoot( int projectGroupId, int scmRootId )
778         throws ContinuumException
779     {
780         synchronized( overallDistributedBuildQueues )
781         {
782             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
783             {
784                 OverallDistributedBuildQueue distributedBuildQueue = overallDistributedBuildQueues.get( buildAgentUrl );
785 
786                 try
787                 {
788                     for ( PrepareBuildProjectsTask task : distributedBuildQueue.getProjectsInQueue() )
789                     {
790                         if ( task.getProjectGroupId() == projectGroupId && task.getProjectScmRootId() == scmRootId )
791                         {
792                             return distributedBuildQueue;
793                         }
794                     }
795                 }
796                 catch ( TaskQueueException e )
797                 {
798                     log.error( "Error occurred while retrieving distributed build queue of projectGroupId=" + projectGroupId + " scmRootId=" + scmRootId, e );
799                     throw new ContinuumException( "Error occurred while retrieving distributed build queue of group", e );
800                 }
801             }
802         }
803 
804         return null;
805     }
806 
807     private OverallDistributedBuildQueue getOverallDistributedBuildQueueByGroup( int projectGroupId )
808         throws ContinuumException
809     {
810         synchronized( overallDistributedBuildQueues )
811         {
812             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
813             {
814                 OverallDistributedBuildQueue distributedBuildQueue = overallDistributedBuildQueues.get( buildAgentUrl );
815 
816                 try
817                 {
818                     
819                     for ( PrepareBuildProjectsTask task : distributedBuildQueue.getProjectsInQueue() )
820                     {
821                         if ( task.getProjectGroupId() == projectGroupId )
822                         {
823                             return distributedBuildQueue;
824                         }
825                     }
826 
827                     Task task = distributedBuildQueue.getDistributedBuildTaskQueueExecutor().getCurrentTask();
828                     if ( task != null && ( (PrepareBuildProjectsTask) task ).getProjectGroupId() == projectGroupId )
829                     {
830                         return distributedBuildQueue;
831                     }
832 
833                     SlaveBuildAgentTransportClient client = new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
834 
835                     if ( client.isProjectGroupInQueue( projectGroupId ) )
836                     {
837                         return distributedBuildQueue;
838                     }
839                 }
840                 catch ( TaskQueueException e )
841                 {
842                     log.error( "Error occurred while retrieving distributed build queue of projectGroupId=" + projectGroupId, e );
843                     throw new ContinuumException( "Error occurred while retrieving distributed build queue of group", e );
844                 }
845                 catch ( MalformedURLException e )
846                 {
847                     log.error( "Error occurred while retrieving distributed build queue of projectGroupId=" + projectGroupId + 
848                                ": Invalid build agent url " + buildAgentUrl );
849                     throw new ContinuumException( "Error occurred while retrieving distributed build queue of projectGroupId=" + projectGroupId + 
850                                ": Invalid build agent url " + buildAgentUrl );
851                 }
852                 catch ( Exception e )
853                 {
854                     log.error( "Error occurred while retrieving distributed build queue of projectGroupId=" + projectGroupId, e );
855                     throw new ContinuumException( "Error occurred while retrieving distributed build queue of group", e );
856                 }
857             }
858         }
859 
860         return null;
861     }
862 
863     // need to change this
864     private OverallDistributedBuildQueue getOverallDistributedBuildQueueByHashCode( int hashCode )
865         throws ContinuumException
866     {
867         synchronized( overallDistributedBuildQueues )
868         {
869             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
870             {
871                 OverallDistributedBuildQueue distributedBuildQueue = overallDistributedBuildQueues.get( buildAgentUrl );
872 
873                 try
874                 {
875                     for ( PrepareBuildProjectsTask task : distributedBuildQueue.getProjectsInQueue() )
876                     {
877                         if ( task.getHashCode() == hashCode )
878                         {
879                             return distributedBuildQueue;
880                         }
881                     }
882                 }
883                 catch ( TaskQueueException e )
884                 {
885                     log.error( "Error occurred while retrieving distributed build queue", e );
886                     throw new ContinuumException( "Error occurred while retrieving distributed build queue", e );
887                 }
888             }
889         }
890 
891         return null;
892     }
893 
894     private OverallDistributedBuildQueue getOverallDistributedBuildQueueByAgentGroup( Map<Integer, Integer> projectsAndBuildDefinitionsMap )
895         throws ContinuumException
896     {
897         OverallDistributedBuildQueue whereToBeQueued = null;
898 
899         BuildAgentGroupConfiguration buildAgentGroup = getBuildAgentGroup( projectsAndBuildDefinitionsMap );
900 
901         if ( buildAgentGroup != null )
902         {
903             List<BuildAgentConfiguration> buildAgents = buildAgentGroup.getBuildAgents();
904 
905             if ( buildAgents != null && buildAgents.size() > 0 )
906             {
907                 List<String> buildAgentUrls = new ArrayList<String>();
908                 
909                 for ( BuildAgentConfiguration buildAgent : buildAgents )
910                 {
911                     buildAgentUrls.add( buildAgent.getUrl() );
912                 }
913 
914                 synchronized( overallDistributedBuildQueues )
915                 {
916                     int idx = 0;
917                     int size = 0;
918                     
919                     for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
920                     {
921                         if ( ( !buildAgentUrls.isEmpty() && buildAgentUrls.contains( buildAgentUrl ) ) || buildAgentUrls.isEmpty() )
922                         {
923                             OverallDistributedBuildQueue distributedBuildQueue = overallDistributedBuildQueues.get( buildAgentUrl );
924 
925                             if ( distributedBuildQueue != null )
926                             {
927                                 try
928                                 {
929                                     SlaveBuildAgentTransportClient client = new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
930                                     int agentBuildSize = client.getBuildSizeOfAgent();
931 
932                                     if ( idx == 0 )
933                                     {
934                                         whereToBeQueued = distributedBuildQueue;
935                                         size = agentBuildSize;
936                                     }
937 
938                                     if ( agentBuildSize < size )
939                                     {
940                                         whereToBeQueued = distributedBuildQueue;
941                                         size = agentBuildSize;
942                                     }
943                                 }
944                                 catch ( MalformedURLException e )
945                                 {
946                                     log.error( "Error occurred while retrieving distributed build queue: Invalid build agent url " + buildAgentUrl );
947                                 }
948                                 catch ( Exception e )
949                                 {
950                                     log.error( "Error occurred while retrieving distributed build queue ", e );
951                                 }
952                             }
953                         }
954                     }
955                 }
956             }
957         }
958         return whereToBeQueued;
959     }
960 
961     private OverallDistributedBuildQueue getOverallDistributedBuildQueue()
962         throws ContinuumException
963     {
964         OverallDistributedBuildQueue whereToBeQueued = null;
965 
966         synchronized ( overallDistributedBuildQueues )
967         {
968             if ( overallDistributedBuildQueues.isEmpty() )
969             {
970                 log.info( "No distributed build queues are configured for build agents" );
971                 return null;
972             }
973 
974             int idx = 0;
975             int size = 0;
976 
977             for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
978             {
979                 OverallDistributedBuildQueue distributedBuildQueue = overallDistributedBuildQueues.get( buildAgentUrl );
980 
981                 if ( distributedBuildQueue != null )
982                 {
983                     try
984                     {
985                         SlaveBuildAgentTransportClient client = new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ) );
986                         int agentBuildSize = client.getBuildSizeOfAgent();
987 
988                         if ( idx == 0 )
989                         {
990                             whereToBeQueued = distributedBuildQueue;
991                             size = agentBuildSize;
992                         }
993 
994                         if ( agentBuildSize < size )
995                         {
996                             whereToBeQueued = distributedBuildQueue;
997                             size = agentBuildSize;
998                         }
999                     }
1000                     catch ( MalformedURLException e )
1001                     {
1002                         log.error( "Error occurred while retrieving distributed build queue: invalid build agent url " + buildAgentUrl );
1003                     }
1004                     catch ( Exception e )
1005                     {
1006                         log.error( "Error occurred while retrieving distributed build queue", e );
1007                         throw new ContinuumException( "Error occurred while retrieving distributed build queue", e );
1008                     }
1009                 }
1010 
1011                 idx++;
1012             }
1013         }
1014 
1015         return whereToBeQueued;
1016     }
1017 
1018     private BuildAgentGroupConfiguration getBuildAgentGroup( Map<Integer, Integer> projectsAndBuildDefinitions )
1019         throws ContinuumException
1020     {
1021 
1022         if ( projectsAndBuildDefinitions == null )
1023         {
1024             return null;
1025         }
1026 
1027         try
1028         {
1029             List<Project> projects = new ArrayList<Project>();
1030 
1031             for ( Integer projectId : projectsAndBuildDefinitions.keySet() )
1032             {
1033                 projects.add( projectDao.getProjectWithDependencies( projectId ) );
1034             }
1035 
1036             projects = ProjectSorter.getSortedProjects( projects, null );
1037 
1038             int buildDefinitionId = projectsAndBuildDefinitions.get( projects.get( 0 ).getId() );
1039             BuildDefinition buildDefinition = buildDefinitionDao.getBuildDefinition( buildDefinitionId );
1040 
1041             Profile profile = buildDefinition.getProfile();
1042 
1043             if ( profile != null && !StringUtils.isEmpty( profile.getBuildAgentGroup() ) )
1044             {
1045                 String groupName = profile.getBuildAgentGroup();
1046 
1047                 BuildAgentGroupConfiguration buildAgentGroup = configurationService.getBuildAgentGroup( groupName );
1048 
1049                 return buildAgentGroup;
1050             }
1051         }
1052         catch ( ContinuumStoreException e )
1053         {
1054             log.error( "Error while getting build agent group", e );
1055             throw new ContinuumException( "Error while getting build agent group", e );
1056         }
1057 
1058         log.info( "profile build agent group is null" );
1059 
1060         return null;
1061     }
1062  
1063     private PrepareBuildProjectsTask getPrepareBuildProjectsTask( Map context )
1064     {
1065         int projectGroupId = ContinuumBuildConstant.getProjectGroupId( context );
1066         int scmRootId = ContinuumBuildConstant.getScmRootId( context );
1067         String scmRootAddress = ContinuumBuildConstant.getScmRootAddress( context );
1068         int trigger = ContinuumBuildConstant.getTrigger( context );
1069 
1070         return new PrepareBuildProjectsTask( null, trigger, projectGroupId, null, scmRootAddress, scmRootId );
1071     }
1072 
1073     private BuildProjectTask getBuildProjectTask( Map context )
1074     {
1075         int projectId = ContinuumBuildConstant.getProjectId( context );
1076         int buildDefinitionId = ContinuumBuildConstant.getBuildDefinitionId( context );
1077         int trigger = ContinuumBuildConstant.getTrigger( context );
1078         int projectGroupId = ContinuumBuildConstant.getProjectGroupId( context );
1079         String buildDefinitionLabel = ContinuumBuildConstant.getBuildDefinitionLabel( context );
1080 
1081         return new BuildProjectTask( projectId, buildDefinitionId, trigger, null, buildDefinitionLabel, null, projectGroupId );
1082     }
1083 }