View Javadoc

1   package org.apache.continuum.buildagent;
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.io.File;
23  import java.io.FileReader;
24  import java.io.IOException;
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.regex.Matcher;
31  import java.util.regex.Pattern;
32  
33  import org.apache.commons.lang.ArrayUtils;
34  import org.apache.commons.lang.StringEscapeUtils;
35  import org.apache.continuum.buildagent.buildcontext.BuildContext;
36  import org.apache.continuum.buildagent.buildcontext.manager.BuildContextManager;
37  import org.apache.continuum.buildagent.configuration.BuildAgentConfigurationService;
38  import org.apache.continuum.buildagent.manager.BuildAgentReleaseManager;
39  import org.apache.continuum.buildagent.model.Installation;
40  import org.apache.continuum.buildagent.taskqueue.PrepareBuildProjectsTask;
41  import org.apache.continuum.buildagent.taskqueue.manager.BuildAgentTaskQueueManager;
42  import org.apache.continuum.buildagent.utils.ContinuumBuildAgentUtil;
43  import org.apache.continuum.buildagent.utils.WorkingCopyContentGenerator;
44  import org.apache.continuum.taskqueue.BuildProjectTask;
45  import org.apache.continuum.taskqueue.manager.TaskQueueManagerException;
46  import org.apache.maven.continuum.ContinuumException;
47  import org.apache.maven.continuum.model.project.BuildResult;
48  import org.apache.maven.continuum.model.scm.ChangeFile;
49  import org.apache.maven.continuum.model.scm.ChangeSet;
50  import org.apache.maven.continuum.model.scm.ScmResult;
51  import org.apache.maven.continuum.project.ContinuumProjectState;
52  import org.apache.maven.continuum.release.ContinuumReleaseException;
53  import org.apache.maven.model.Model;
54  import org.apache.maven.model.Plugin;
55  import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
56  import org.apache.maven.shared.release.ReleaseResult;
57  import org.apache.maven.shared.release.versions.DefaultVersionInfo;
58  import org.apache.maven.shared.release.versions.VersionInfo;
59  import org.codehaus.plexus.taskqueue.TaskQueueException;
60  import org.codehaus.plexus.util.FileUtils;
61  import org.codehaus.plexus.util.StringUtils;
62  import org.codehaus.plexus.util.xml.Xpp3Dom;
63  import org.slf4j.Logger;
64  import org.slf4j.LoggerFactory;
65  
66  /**
67   * @plexus.component role="org.apache.continuum.buildagent.ContinuumBuildAgentService"
68   */
69  public class ContinuumBuildAgentServiceImpl
70      implements ContinuumBuildAgentService
71  {
72      private static final Logger log = LoggerFactory.getLogger( ContinuumBuildAgentServiceImpl.class );
73  
74      /**
75       * @plexus.requirement
76       */
77      private BuildAgentConfigurationService buildAgentConfigurationService;
78  
79      /**
80       * @plexus.requirement
81       */
82      private BuildAgentTaskQueueManager buildAgentTaskQueueManager;
83  
84      /**
85       * @plexus.requirement
86       */
87      private BuildContextManager buildContextManager;
88  
89      /**
90       * @plexus.requirement
91       */
92      private WorkingCopyContentGenerator generator;
93  
94      /**
95       * @plexus.requirement
96       */
97      private BuildAgentReleaseManager buildAgentReleaseManager;
98  
99      public void buildProjects( List<Map<String, Object>> projectsBuildContext )
100         throws ContinuumBuildAgentException
101     {
102         List<BuildContext> buildContextList = initializeBuildContext( projectsBuildContext );
103 
104         PrepareBuildProjectsTask task = createPrepareBuildProjectsTask( buildContextList );
105 
106         if ( task == null )
107         {
108             return;
109         }
110 
111         try
112         {
113             buildAgentTaskQueueManager.getPrepareBuildQueue().put( task );
114         }
115         catch ( TaskQueueException e )
116         {
117             throw new ContinuumBuildAgentException( "Error while enqueuing projects", e );
118         }
119 
120     }
121 
122     public List<Map<String, String>> getAvailableInstallations()
123         throws ContinuumBuildAgentException
124     {
125         List<Map<String, String>> installationsList = new ArrayList<Map<String, String>>();
126 
127         List<Installation> installations = buildAgentConfigurationService.getAvailableInstallations();
128 
129         for ( Installation installation : installations )
130         {
131             Map<String, String> map = new HashMap<String, String>();
132 
133             if ( StringUtils.isBlank( installation.getName() ) )
134             {
135                 map.put( ContinuumBuildAgentUtil.KEY_INSTALLATION_NAME, "" );
136             }
137             else
138             {
139                 map.put( ContinuumBuildAgentUtil.KEY_INSTALLATION_NAME, installation.getName() );
140             }
141 
142             if ( StringUtils.isBlank( installation.getType() ) )
143             {
144                 map.put( ContinuumBuildAgentUtil.KEY_INSTALLATION_TYPE, "" );
145             }
146             else
147             {
148                 map.put( ContinuumBuildAgentUtil.KEY_INSTALLATION_TYPE, installation.getType() );
149             }
150 
151             if ( StringUtils.isBlank( installation.getVarName() ) )
152             {
153                 map.put( ContinuumBuildAgentUtil.KEY_INSTALLATION_VAR_NAME, "" );
154             }
155             else
156             {
157                 map.put( ContinuumBuildAgentUtil.KEY_INSTALLATION_VAR_VALUE, installation.getVarValue() );
158             }
159 
160             if ( StringUtils.isBlank( installation.getVarValue() ) )
161             {
162                 map.put( ContinuumBuildAgentUtil.KEY_INSTALLATION_VAR_VALUE, "" );
163             }
164             else
165             {
166                 map.put( ContinuumBuildAgentUtil.KEY_INSTALLATION_VAR_VALUE, installation.getVarValue() );
167             }
168 
169             installationsList.add( map );
170         }
171 
172         return installationsList;
173     }
174 
175     public Map<String, Object> getBuildResult( int projectId )
176         throws ContinuumBuildAgentException
177     {
178         Map<String, Object> result = new HashMap<String, Object>();
179 
180         int currentBuildId = 0;
181 
182         try
183         {
184             currentBuildId = buildAgentTaskQueueManager.getIdOfProjectCurrentlyBuilding();
185         }
186         catch ( TaskQueueManagerException e )
187         {
188             throw new ContinuumBuildAgentException( e.getMessage(), e );
189         }
190 
191         if ( projectId == currentBuildId )
192         {
193             BuildContext buildContext = buildContextManager.getBuildContext( projectId );
194 
195             result.put( ContinuumBuildAgentUtil.KEY_PROJECT_ID, buildContext.getProjectId() );
196             result.put( ContinuumBuildAgentUtil.KEY_BUILD_DEFINITION_ID, buildContext.getBuildDefinitionId() );
197             result.put( ContinuumBuildAgentUtil.KEY_TRIGGER, buildContext.getTrigger() );
198 
199             BuildResult buildResult = buildContext.getBuildResult();
200 
201             if ( buildResult != null )
202             {
203                 if ( buildResult.getStartTime() <= 0 )
204                 {
205                     result.put( ContinuumBuildAgentUtil.KEY_START_TIME,
206                                 Long.toString( buildContext.getBuildStartTime() ) );
207                 }
208                 else
209                 {
210                     result.put( ContinuumBuildAgentUtil.KEY_START_TIME, Long.toString( buildResult.getStartTime() ) );
211                 }
212 
213                 if ( buildResult.getError() == null )
214                 {
215                     result.put( ContinuumBuildAgentUtil.KEY_BUILD_ERROR, "" );
216                 }
217                 else
218                 {
219                     result.put( ContinuumBuildAgentUtil.KEY_BUILD_ERROR, buildResult.getError() );
220                 }
221 
222                 result.put( ContinuumBuildAgentUtil.KEY_BUILD_STATE, buildResult.getState() );
223                 result.put( ContinuumBuildAgentUtil.KEY_END_TIME, Long.toString( buildResult.getEndTime() ) );
224                 result.put( ContinuumBuildAgentUtil.KEY_BUILD_EXIT_CODE, buildResult.getExitCode() );
225             }
226             else
227             {
228                 result.put( ContinuumBuildAgentUtil.KEY_START_TIME, Long.toString( buildContext.getBuildStartTime() ) );
229                 result.put( ContinuumBuildAgentUtil.KEY_END_TIME, Long.toString( 0 ) );
230                 result.put( ContinuumBuildAgentUtil.KEY_BUILD_STATE, ContinuumProjectState.BUILDING );
231                 result.put( ContinuumBuildAgentUtil.KEY_BUILD_ERROR, "" );
232                 result.put( ContinuumBuildAgentUtil.KEY_BUILD_EXIT_CODE, 0 );
233             }
234 
235             String buildOutput = getBuildOutputText( projectId );
236             if ( buildOutput == null )
237             {
238                 result.put( ContinuumBuildAgentUtil.KEY_BUILD_OUTPUT, "" );
239             }
240             else
241             {
242                 result.put( ContinuumBuildAgentUtil.KEY_BUILD_OUTPUT, buildOutput );
243             }
244 
245             result.put( ContinuumBuildAgentUtil.KEY_SCM_RESULT,
246                         ContinuumBuildAgentUtil.createScmResult( buildContext ) );
247         }
248         return result;
249     }
250 
251     public void cancelBuild()
252         throws ContinuumBuildAgentException
253     {
254         try
255         {
256             buildAgentTaskQueueManager.cancelBuild();
257         }
258         catch ( TaskQueueManagerException e )
259         {
260             throw new ContinuumBuildAgentException( e.getMessage(), e );
261         }
262     }
263 
264     public String generateWorkingCopyContent( int projectId, String userDirectory, String baseUrl,
265                                               String imagesBaseUrl )
266         throws ContinuumBuildAgentException
267     {
268         File workingDirectory = buildAgentConfigurationService.getWorkingDirectory( projectId );
269 
270         try
271         {
272             List<File> files = ContinuumBuildAgentUtil.getFiles( userDirectory, workingDirectory );
273             return generator.generate( files, baseUrl, imagesBaseUrl, workingDirectory );
274         }
275         catch ( ContinuumException e )
276         {
277             log.error( "Failed to generate working copy content", e );
278         }
279 
280         return "";
281     }
282 
283     public String getProjectFileContent( int projectId, String directory, String filename )
284         throws ContinuumBuildAgentException
285     {
286         String relativePath = "\\.\\./"; // prevent users from using relative paths.
287         Pattern pattern = Pattern.compile( relativePath );
288         Matcher matcher = pattern.matcher( directory );
289         String filteredDirectory = matcher.replaceAll( "" );
290 
291         matcher = pattern.matcher( filename );
292         String filteredFilename = matcher.replaceAll( "" );
293 
294         File workingDirectory = buildAgentConfigurationService.getWorkingDirectory( projectId );
295 
296         File fileDirectory = new File( workingDirectory, filteredDirectory );
297 
298         File userFile = new File( fileDirectory, filteredFilename );
299 
300         try
301         {
302             return FileUtils.fileRead( userFile );
303         }
304         catch ( IOException e )
305         {
306             throw new ContinuumBuildAgentException( "Can't read file " + filename, e );
307         }
308     }
309 
310     public Map<String, Object> getReleasePluginParameters( int projectId, String pomFilename )
311         throws ContinuumBuildAgentException
312     {
313         Map<String, Object> releaseParameters = new HashMap<String, Object>();
314 
315         String workingDirectory = buildAgentConfigurationService.getWorkingDirectory( projectId ).getPath();
316 
317         MavenXpp3Reader pomReader = new MavenXpp3Reader();
318         try
319         {
320             Model model = pomReader.read( new FileReader( new File( workingDirectory, pomFilename ) ) );
321 
322             if ( model.getBuild() != null && model.getBuild().getPlugins() != null )
323             {
324                 for ( Plugin plugin : (List<Plugin>) model.getBuild().getPlugins() )
325                 {
326                     if ( plugin.getGroupId() != null && plugin.getGroupId().equals( "org.apache.maven.plugins" ) &&
327                         plugin.getArtifactId() != null && plugin.getArtifactId().equals( "maven-release-plugin" ) )
328                     {
329                         Xpp3Dom dom = (Xpp3Dom) plugin.getConfiguration();
330 
331                         if ( dom != null )
332                         {
333                             Xpp3Dom configuration = dom.getChild( "releaseLabel" );
334                             if ( configuration != null )
335                             {
336                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_SCM_TAG, configuration.getValue() );
337                             }
338                             else
339                             {
340                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_SCM_TAG, "" );
341                             }
342 
343                             configuration = dom.getChild( "tag" );
344                             if ( configuration != null )
345                             {
346                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_SCM_TAG, configuration.getValue() );
347                             }
348                             else
349                             {
350                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_SCM_TAG, "" );
351                             }
352 
353                             configuration = dom.getChild( "tagBase" );
354                             if ( configuration != null )
355                             {
356                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_SCM_TAGBASE,
357                                                        configuration.getValue() );
358                             }
359                             else
360                             {
361                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_SCM_TAGBASE, "" );
362                             }
363 
364                             configuration = dom.getChild( "preparationGoals" );
365                             if ( configuration != null )
366                             {
367                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_PREPARE_GOALS,
368                                                        configuration.getValue() );
369                             }
370                             else
371                             {
372                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_PREPARE_GOALS, "" );
373                             }
374 
375                             configuration = dom.getChild( "arguments" );
376                             if ( configuration != null )
377                             {
378                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_ARGUMENTS,
379                                                        configuration.getValue() );
380                             }
381                             else
382                             {
383                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_ARGUMENTS, "" );
384                             }
385 
386                             configuration = dom.getChild( "scmCommentPrefix" );
387                             if ( configuration != null )
388                             {
389                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_SCM_COMMENT_PREFIX,
390                                                        configuration.getValue() );
391                             }
392                             else
393                             {
394                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_SCM_COMMENT_PREFIX, "" );
395                             }
396 
397                             configuration = dom.getChild( "autoVersionSubmodules" );
398                             if ( configuration != null )
399                             {
400                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_AUTO_VERSION_SUBMODULES,
401                                                        Boolean.valueOf( configuration.getValue() ) );
402                             }
403                             else
404                             {
405                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_AUTO_VERSION_SUBMODULES, false );
406                             }
407 
408                             configuration = dom.getChild( "addSchema" );
409                             if ( configuration != null )
410                             {
411                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_ADD_SCHEMA,
412                                                        Boolean.valueOf( configuration.getValue() ) );
413                             }
414                             else
415                             {
416                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_ADD_SCHEMA, false );
417                             }
418 
419                             configuration = dom.getChild( "useReleaseProfile" );
420                             if ( configuration != null )
421                             {
422                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_USE_RELEASE_PROFILE,
423                                                        Boolean.valueOf( configuration.getValue() ) );
424                             }
425                             else
426                             {
427                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_USE_RELEASE_PROFILE, false );
428                             }
429 
430                             configuration = dom.getChild( "goals" );
431                             if ( configuration != null )
432                             {
433                                 String goals = configuration.getValue();
434                                 if ( model.getDistributionManagement() != null &&
435                                     model.getDistributionManagement().getSite() != null )
436                                 {
437                                     goals += "site-deploy";
438                                 }
439 
440                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_GOALS, goals );
441                             }
442                             else
443                             {
444                                 releaseParameters.put( ContinuumBuildAgentUtil.KEY_GOALS, "" );
445                             }
446                         }
447                     }
448                 }
449             }
450         }
451         catch ( Exception e )
452         {
453             throw new ContinuumBuildAgentException( "Error getting release plugin parameters from pom file", e );
454         }
455 
456         return releaseParameters;
457     }
458 
459     public List<Map<String, String>> processProject( int projectId, String pomFilename, boolean autoVersionSubmodules )
460         throws ContinuumBuildAgentException
461     {
462         List<Map<String, String>> projects = new ArrayList<Map<String, String>>();
463 
464         String workingDirectory = buildAgentConfigurationService.getWorkingDirectory( projectId ).getPath();
465 
466         try
467         {
468             processProject( workingDirectory, pomFilename, autoVersionSubmodules, projects );
469         }
470         catch ( Exception e )
471         {
472             throw new ContinuumBuildAgentException( "Unable to process project " + projectId, e );
473         }
474 
475         return projects;
476     }
477 
478     public String releasePrepare( Map project, Map properties, Map releaseVersion, Map developmentVersion,
479                                   Map<String, String> environments )
480         throws ContinuumBuildAgentException
481     {
482         try
483         {
484             return buildAgentReleaseManager.releasePrepare( project, properties, releaseVersion, developmentVersion,
485                                                             environments );
486         }
487         catch ( ContinuumReleaseException e )
488         {
489             throw new ContinuumBuildAgentException( "Unable to prepare release", e );
490         }
491     }
492 
493     public Map<String, Object> getReleaseResult( String releaseId )
494         throws ContinuumBuildAgentException
495     {
496         ReleaseResult result = buildAgentReleaseManager.getReleaseResult( releaseId );
497 
498         Map<String, Object> map = new HashMap<String, Object>();
499         map.put( ContinuumBuildAgentUtil.KEY_START_TIME, Long.toString( result.getStartTime() ) );
500         map.put( ContinuumBuildAgentUtil.KEY_END_TIME, Long.toString( result.getEndTime() ) );
501         map.put( ContinuumBuildAgentUtil.KEY_RELEASE_RESULT_CODE, result.getResultCode() );
502         map.put( ContinuumBuildAgentUtil.KEY_RELEASE_OUTPUT, result.getOutput() );
503 
504         return map;
505     }
506 
507     public Map<String, Object> getListener( String releaseId )
508         throws ContinuumBuildAgentException
509     {
510         return buildAgentReleaseManager.getListener( releaseId );
511     }
512 
513     public void removeListener( String releaseId )
514     {
515         buildAgentReleaseManager.removeListener( releaseId );
516     }
517 
518     public String getPreparedReleaseName( String releaseId )
519     {
520         return buildAgentReleaseManager.getPreparedReleaseName( releaseId );
521     }
522 
523     public void releasePerform( String releaseId, String goals, String arguments, boolean useReleaseProfile,
524                                 Map repository )
525         throws ContinuumBuildAgentException
526     {
527         try
528         {
529             buildAgentReleaseManager.releasePerform( releaseId, goals, arguments, useReleaseProfile, repository );
530         }
531         catch ( ContinuumReleaseException e )
532         {
533             throw new ContinuumBuildAgentException( "Unable to perform release " + releaseId, e );
534         }
535     }
536 
537     public String releasePerformFromScm( String goals, String arguments, boolean useReleaseProfile, Map repository,
538                                          String scmUrl, String scmUsername, String scmPassword, String scmTag,
539                                          String scmTagBase, Map<String, String> environments )
540         throws ContinuumBuildAgentException
541     {
542         try
543         {
544             return buildAgentReleaseManager.releasePerformFromScm( goals, arguments, useReleaseProfile, repository,
545                                                                    scmUrl, scmUsername, scmPassword, scmTag, scmTagBase,
546                                                                    environments );
547         }
548         catch ( ContinuumReleaseException e )
549         {
550             throw new ContinuumBuildAgentException( "Unable to perform release from scm", e );
551         }
552     }
553 
554     public String releaseCleanup( String releaseId )
555         throws ContinuumBuildAgentException
556     {
557         return buildAgentReleaseManager.releaseCleanup( releaseId );
558     }
559 
560     public void releaseRollback( String releaseId, int projectId )
561         throws ContinuumBuildAgentException
562     {
563         try
564         {
565             buildAgentReleaseManager.releaseRollback( releaseId, projectId );
566         }
567         catch ( ContinuumReleaseException e )
568         {
569             throw new ContinuumBuildAgentException( "Unable to rollback release " + releaseId, e );
570         }
571     }
572 
573     public int getBuildSizeOfAgent()
574     {
575         int size = 0;
576         
577         try
578         {
579             if ( buildAgentTaskQueueManager.getCurrentProjectInBuilding() != null )
580             {
581                 size++;
582             }
583 
584             if ( buildAgentTaskQueueManager.getCurrentProjectInPrepareBuild() != null )
585             {
586                 size++;
587             }
588 
589             size = size + buildAgentTaskQueueManager.getProjectsInBuildQueue().size();
590 
591             size = size + buildAgentTaskQueueManager.getProjectsInPrepareBuildQueue().size();
592         }
593         catch ( TaskQueueManagerException e )
594         {
595             log.error( "Error occurred while getting build size of agent" );
596         }
597 
598         return size;
599     }
600 
601     public List<Map<String, Object>> getProjectsInPrepareBuildQueue()
602         throws ContinuumBuildAgentException
603     {
604         try
605         {
606             List<Map<String, Object>> projects = new ArrayList<Map<String, Object>>();
607 
608             for ( PrepareBuildProjectsTask task : buildAgentTaskQueueManager.getProjectsInPrepareBuildQueue() )
609             {
610                 Map<String, Object> map = new HashMap<String, Object>();
611                 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_GROUP_ID, new Integer( task.getProjectGroupId() ) );
612                 map.put( ContinuumBuildAgentUtil.KEY_SCM_ROOT_ID, new Integer( task.getScmRootId() ) );
613                 map.put( ContinuumBuildAgentUtil.KEY_SCM_ROOT_ADDRESS, task.getScmRootAddress() );
614                 map.put( ContinuumBuildAgentUtil.KEY_TRIGGER, new Integer( task.getTrigger() ) );
615 
616                 projects.add( map );
617             }
618 
619             return projects;
620         }
621         catch( TaskQueueManagerException e )
622         {
623             log.error( "Error occurred while retrieving projects in prepare build queue", e );
624             throw new ContinuumBuildAgentException( "Error occurred while retrieving projects in prepare build queue", e );
625         }
626     }
627 
628     public List<Map<String, Object>> getProjectsInBuildQueue()
629         throws ContinuumBuildAgentException
630     {
631         try
632         {
633             List<Map<String, Object>> projects = new ArrayList<Map<String, Object>>();
634 
635             for ( BuildProjectTask task : buildAgentTaskQueueManager.getProjectsInBuildQueue() )
636             {
637                 Map<String, Object> map = new HashMap<String, Object>();
638                 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_ID, new Integer( task.getProjectId() ) );
639                 map.put( ContinuumBuildAgentUtil.KEY_BUILD_DEFINITION_ID, new Integer( task.getBuildDefinitionId() ) );
640                 map.put( ContinuumBuildAgentUtil.KEY_TRIGGER, new Integer( task.getTrigger() ) );
641                 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_GROUP_ID, new Integer( task.getProjectGroupId() ) );
642                 map.put( ContinuumBuildAgentUtil.KEY_BUILD_DEFINITION_LABEL, task.getBuildDefinitionLabel() );
643 
644                 projects.add( map );
645             }
646 
647             return projects;
648         }
649         catch( TaskQueueManagerException e )
650         {
651             log.error( "Error occurred while retrieving projects in build queue", e );
652             throw new ContinuumBuildAgentException( "Error occurred while retrieving projects in build queue", e );
653         }
654     }
655 
656     public Map<String, Object> getProjectCurrentlyPreparingBuild()
657         throws ContinuumBuildAgentException
658     {
659         try
660         {
661             Map<String, Object> project = new HashMap<String, Object>();
662 
663             PrepareBuildProjectsTask task = buildAgentTaskQueueManager.getCurrentProjectInPrepareBuild();
664 
665             if ( task != null )
666             {
667                 project.put( ContinuumBuildAgentUtil.KEY_PROJECT_GROUP_ID, new Integer( task.getProjectGroupId() ) );
668                 project.put( ContinuumBuildAgentUtil.KEY_SCM_ROOT_ID, new Integer( task.getScmRootId() ) );
669                 project.put( ContinuumBuildAgentUtil.KEY_SCM_ROOT_ADDRESS, task.getScmRootAddress() );
670                 project.put( ContinuumBuildAgentUtil.KEY_TRIGGER, task.getTrigger() );
671             }
672 
673             return project;
674         }
675         catch ( TaskQueueManagerException e )
676         {
677             log.error( "Error occurred while retrieving current project in prepare build", e );
678             throw new ContinuumBuildAgentException( "Error occurred while retrieving current project in prepare build", e );
679         }
680     }
681 
682     public Map<String, Object> getProjectCurrentlyBuilding()
683         throws ContinuumBuildAgentException
684     {
685         try
686         {
687             Map<String, Object> project = new HashMap<String, Object>();
688 
689             BuildProjectTask task = buildAgentTaskQueueManager.getCurrentProjectInBuilding();
690 
691             if ( task != null )
692             {
693                 project.put( ContinuumBuildAgentUtil.KEY_PROJECT_ID, new Integer( task.getProjectId() ) );
694                 project.put( ContinuumBuildAgentUtil.KEY_BUILD_DEFINITION_ID, new Integer( task.getBuildDefinitionId() ) );
695                 project.put( ContinuumBuildAgentUtil.KEY_TRIGGER, new Integer( task.getTrigger() ) );
696                 project.put( ContinuumBuildAgentUtil.KEY_PROJECT_GROUP_ID, new Integer( task.getProjectGroupId() ) );
697                 project.put( ContinuumBuildAgentUtil.KEY_BUILD_DEFINITION_LABEL, task.getBuildDefinitionLabel() );
698             }
699 
700             return project;
701         }
702         catch ( TaskQueueManagerException e )
703         {
704             log.error( "Error occurred while retrieving current project in building", e );
705             throw new ContinuumBuildAgentException( "Error occurred while retrieving current project in building", e );
706         }
707     }
708 
709     public boolean isProjectGroupInQueue( int projectGroupId )
710     {
711         try
712         {
713             PrepareBuildProjectsTask currentPrepareBuildTask = buildAgentTaskQueueManager.getCurrentProjectInPrepareBuild();
714 
715             if ( currentPrepareBuildTask != null && currentPrepareBuildTask.getProjectGroupId() == projectGroupId )
716             {
717                 return true;
718             }
719 
720             BuildProjectTask currentBuildTask = buildAgentTaskQueueManager.getCurrentProjectInBuilding();
721 
722             if ( currentBuildTask != null && currentBuildTask.getProjectGroupId() == projectGroupId )
723             {
724                 return true;
725             }
726 
727             for ( PrepareBuildProjectsTask task : buildAgentTaskQueueManager.getProjectsInPrepareBuildQueue() )
728             {
729                 if ( task.getProjectGroupId() == projectGroupId )
730                 {
731                     return true;
732                 }
733             }
734 
735             for ( BuildProjectTask task : buildAgentTaskQueueManager.getProjectsInBuildQueue() )
736             {
737                 if ( task.getProjectGroupId() == projectGroupId )
738                 {
739                     return true;
740                 }
741             }
742         }
743         catch ( TaskQueueManagerException e )
744         {
745             log.error( "Error while checking if project group " + projectGroupId + " is queued in agent", e);
746         }
747 
748         return false;
749     }
750 
751     public boolean isProjectCurrentlyBuilding( int projectId )
752     {
753         try
754         {
755             BuildProjectTask currentBuildTask = buildAgentTaskQueueManager.getCurrentProjectInBuilding();
756 
757             if ( currentBuildTask != null && currentBuildTask.getProjectId() == projectId )
758             {
759                 return true;
760             }
761         }
762         catch ( TaskQueueManagerException e )
763         {
764             log.error( "Error occurred while checking if project " + projectId + " is currently building in agent", e );
765         }
766 
767         return false;
768     }
769 
770     public boolean isProjectInBuildQueue( int projectId )
771     {
772         try
773         {
774             List<BuildProjectTask> buildTasks = buildAgentTaskQueueManager.getProjectsInBuildQueue();
775 
776             if ( buildTasks != null )
777             {
778                 for ( BuildProjectTask task : buildTasks )
779                 {
780                     if ( task.getProjectId() == projectId )
781                     {
782                         return true;
783                     }
784                 }
785             }
786         }
787         catch ( TaskQueueManagerException e )
788         {
789             log.error( "Error occurred while checking if project " + projectId + " is in build queue of agent", e );
790         }
791 
792         return false;
793     }
794 
795     public boolean removeFromPrepareBuildQueue( int projectGroupId, int scmRootId )
796         throws ContinuumBuildAgentException
797     {
798         try
799         {
800             return buildAgentTaskQueueManager.removeFromPrepareBuildQueue( projectGroupId, scmRootId );
801         }
802         catch ( TaskQueueManagerException e )
803         {
804             log.error( "Error occurred while removing projects from prepare build queue", e );
805             throw new ContinuumBuildAgentException( "Error occurred while removing projects from prepare build queue", e );
806         }
807     }
808 
809     public void removeFromPrepareBuildQueue( List<String> hashCodes )
810         throws ContinuumBuildAgentException
811     {
812         try
813         {
814             buildAgentTaskQueueManager.removeFromPrepareBuildQueue( listToIntArray( hashCodes ) );
815         }
816         catch ( TaskQueueManagerException e )
817         {
818             log.error( "Error occurred while removing projects from prepare build queue", e );
819             throw new ContinuumBuildAgentException( "Error occurred while removing projects from prepare build queue", e );
820         }
821     }
822 
823     public boolean removeFromBuildQueue( int projectId, int buildDefinitionId )
824         throws ContinuumBuildAgentException
825     {
826         try
827         {
828             return buildAgentTaskQueueManager.removeFromBuildQueue( projectId, buildDefinitionId );
829         }
830         catch ( TaskQueueManagerException e )
831         {
832             log.error( "Error occurred while removing project from build queue", e );
833             throw new ContinuumBuildAgentException( "Error occurred while removing project from build queue ", e );
834         }
835     }
836 
837     public void removeFromBuildQueue( List<String> hashCodes )
838         throws ContinuumBuildAgentException
839     {
840         try
841         {
842             buildAgentTaskQueueManager.removeFromBuildQueue( listToIntArray( hashCodes ) );
843         }
844         catch ( TaskQueueManagerException e )
845         {
846             log.error( "Error occurred while removing projects from build queue", e );
847             throw new ContinuumBuildAgentException( "Error occurred while removing project from build queue ", e );
848         }
849     }
850 
851     private void processProject( String workingDirectory, String pomFilename, boolean autoVersionSubmodules,
852                                  List<Map<String, String>> projects )
853         throws Exception
854     {
855         MavenXpp3Reader pomReader = new MavenXpp3Reader();
856         Model model = pomReader.read( new FileReader( new File( workingDirectory, pomFilename ) ) );
857 
858         if ( model.getGroupId() == null )
859         {
860             model.setGroupId( model.getParent().getGroupId() );
861         }
862 
863         if ( model.getVersion() == null )
864         {
865             model.setVersion( model.getParent().getVersion() );
866         }
867 
868         setProperties( model, projects );
869 
870         if ( !autoVersionSubmodules )
871         {
872             for ( Iterator modules = model.getModules().iterator(); modules.hasNext(); )
873             {
874                 processProject( workingDirectory + "/" + modules.next().toString(), "pom.xml", autoVersionSubmodules,
875                                 projects );
876             }
877         }
878     }
879 
880     private void setProperties( Model model, List<Map<String, String>> projects )
881         throws Exception
882     {
883         Map<String, String> params = new HashMap<String, String>();
884 
885         params.put( "key", model.getGroupId() + ":" + model.getArtifactId() );
886 
887         if ( model.getName() == null )
888         {
889             model.setName( model.getArtifactId() );
890         }
891         params.put( "name", model.getName() );
892 
893         VersionInfo version = new DefaultVersionInfo( model.getVersion() );
894 
895         params.put( "release", version.getReleaseVersionString() );
896         params.put( "dev", version.getNextVersion().getSnapshotVersionString() );
897 
898         projects.add( params );
899     }
900 
901     private List<BuildContext> initializeBuildContext( List<Map<String, Object>> projectsBuildContext )
902     {
903         List<BuildContext> buildContext = new ArrayList<BuildContext>();
904 
905         for ( Map<String, Object> map : projectsBuildContext )
906         {
907             BuildContext context = new BuildContext();
908             context.setProjectId( ContinuumBuildAgentUtil.getProjectId( map ) );
909             context.setProjectVersion( ContinuumBuildAgentUtil.getProjectVersion( map ) );
910             context.setBuildDefinitionId( ContinuumBuildAgentUtil.getBuildDefinitionId( map ) );
911             context.setBuildFile( ContinuumBuildAgentUtil.getBuildFile( map ) );
912             context.setExecutorId( ContinuumBuildAgentUtil.getExecutorId( map ) );
913             context.setGoals( ContinuumBuildAgentUtil.getGoals( map ) );
914             context.setArguments( ContinuumBuildAgentUtil.getArguments( map ) );
915             context.setScmUrl( ContinuumBuildAgentUtil.getScmUrl( map ) );
916             context.setScmUsername( ContinuumBuildAgentUtil.getScmUsername( map ) );
917             context.setScmPassword( ContinuumBuildAgentUtil.getScmPassword( map ) );
918             context.setBuildFresh( ContinuumBuildAgentUtil.isBuildFresh( map ) );
919             context.setProjectGroupId( ContinuumBuildAgentUtil.getProjectGroupId( map ) );
920             context.setProjectGroupName( ContinuumBuildAgentUtil.getProjectGroupName( map ) );
921             context.setScmRootAddress( ContinuumBuildAgentUtil.getScmRootAddress( map ) );
922             context.setScmRootId( ContinuumBuildAgentUtil.getScmRootId( map ) );
923             context.setProjectName( ContinuumBuildAgentUtil.getProjectName( map ) );
924             context.setProjectState( ContinuumBuildAgentUtil.getProjectState( map ) );
925             context.setTrigger( ContinuumBuildAgentUtil.getTrigger( map ) );
926             context.setLocalRepository( ContinuumBuildAgentUtil.getLocalRepository( map ) );
927             context.setBuildNumber( ContinuumBuildAgentUtil.getBuildNumber( map ) );
928             context.setOldScmResult( getScmResult( ContinuumBuildAgentUtil.getOldScmChanges( map ) ) );
929             context.setLatestUpdateDate( ContinuumBuildAgentUtil.getLatestUpdateDate( map ) );
930             context.setBuildAgentUrl( ContinuumBuildAgentUtil.getBuildAgentUrl( map ) );
931             context.setMaxExecutionTime( ContinuumBuildAgentUtil.getMaxExecutionTime( map ) );
932             context.setBuildDefinitionLabel( ContinuumBuildAgentUtil.getBuildDefinitionLabel( map ) );
933             context.setScmTag( ContinuumBuildAgentUtil.getScmTag( map ) );
934 
935             buildContext.add( context );
936         }
937 
938         buildContextManager.addBuildContexts( buildContext );
939 
940         return buildContext;
941     }
942 
943     private String getBuildOutputText( int projectId )
944     {
945         try
946         {
947             File buildOutputFile = buildAgentConfigurationService.getBuildOutputFile( projectId );
948 
949             if ( buildOutputFile.exists() )
950             {
951                 return StringEscapeUtils.escapeHtml( FileUtils.fileRead( buildOutputFile ) );
952             }
953         }
954         catch ( Exception e )
955         {
956             // do not throw exception, just log it
957             log.error( "Error retrieving build output file", e );
958         }
959 
960         return null;
961     }
962 
963     private ScmResult getScmResult( List<Map<String, Object>> scmChanges )
964     {
965         ScmResult scmResult = null;
966 
967         if ( scmChanges != null && scmChanges.size() > 0 )
968         {
969             scmResult = new ScmResult();
970 
971             for ( Map<String, Object> map : scmChanges )
972             {
973                 ChangeSet changeSet = new ChangeSet();
974                 changeSet.setAuthor( ContinuumBuildAgentUtil.getChangeSetAuthor( map ) );
975                 changeSet.setComment( ContinuumBuildAgentUtil.getChangeSetComment( map ) );
976                 changeSet.setDate( ContinuumBuildAgentUtil.getChangeSetDate( map ) );
977                 setChangeFiles( changeSet, map );
978                 scmResult.addChange( changeSet );
979             }
980         }
981 
982         return scmResult;
983     }
984 
985     private void setChangeFiles( ChangeSet changeSet, Map<String, Object> context )
986     {
987         List<Map<String, Object>> files = ContinuumBuildAgentUtil.getChangeSetFiles( context );
988 
989         if ( files != null )
990         {
991             for ( Map<String, Object> map : files )
992             {
993                 ChangeFile changeFile = new ChangeFile();
994                 changeFile.setName( ContinuumBuildAgentUtil.getChangeFileName( map ) );
995                 changeFile.setRevision( ContinuumBuildAgentUtil.getChangeFileRevision( map ) );
996                 changeFile.setStatus( ContinuumBuildAgentUtil.getChangeFileStatus( map ) );
997 
998                 changeSet.addFile( changeFile );
999             }
1000         }
1001     }
1002 
1003     private PrepareBuildProjectsTask createPrepareBuildProjectsTask( List<BuildContext> buildContexts )
1004         throws ContinuumBuildAgentException
1005     {
1006         if ( buildContexts != null && buildContexts.size() > 0 )
1007         {
1008             BuildContext context = buildContexts.get( 0 );
1009             return new PrepareBuildProjectsTask( buildContexts, context.getTrigger(), context.getProjectGroupId(),
1010                                                  context.getScmRootAddress(), context.getScmRootId() );
1011         }
1012         else
1013         {
1014             log.info( "Nothing to build" );
1015             return null;
1016         }
1017     }
1018 
1019     private int[] listToIntArray( List<String> strings )
1020     {
1021         if ( strings == null || strings.isEmpty() )
1022         {
1023             return new int[0];
1024         }
1025         int[] array = new int[0];
1026         for ( String intString : strings )
1027         {
1028             array = ArrayUtils.add( array, Integer.parseInt( intString ) );
1029         }
1030         return array;
1031     }
1032 }