View Javadoc

1   package org.apache.maven.continuum.web.action;
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.util.ArrayList;
23  import java.util.Collection;
24  import java.util.Collections;
25  import java.util.Comparator;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.LinkedHashMap;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.regex.Pattern;
32  
33  import org.apache.commons.collections.ComparatorUtils;
34  import org.apache.commons.lang.StringEscapeUtils;
35  import org.apache.commons.lang.StringUtils;
36  import org.apache.continuum.buildmanager.BuildManagerException;
37  import org.apache.continuum.buildmanager.BuildsManager;
38  import org.apache.continuum.model.project.ProjectScmRoot;
39  import org.apache.continuum.model.repository.LocalRepository;
40  import org.apache.continuum.web.util.AuditLog;
41  import org.apache.continuum.web.util.AuditLogConstants;
42  import org.apache.maven.continuum.ContinuumException;
43  import org.apache.maven.continuum.model.project.BuildDefinition;
44  import org.apache.maven.continuum.model.project.BuildResult;
45  import org.apache.maven.continuum.model.project.Project;
46  import org.apache.maven.continuum.model.project.ProjectDependency;
47  import org.apache.maven.continuum.model.project.ProjectGroup;
48  import org.apache.maven.continuum.project.ContinuumProjectState;
49  import org.apache.maven.continuum.web.bean.ProjectGroupUserBean;
50  import org.apache.maven.continuum.web.exception.AuthorizationRequiredException;
51  import org.codehaus.plexus.redback.rbac.RBACManager;
52  import org.codehaus.plexus.redback.rbac.RbacManagerException;
53  import org.codehaus.plexus.redback.rbac.RbacObjectNotFoundException;
54  import org.codehaus.plexus.redback.rbac.Role;
55  import org.codehaus.plexus.redback.rbac.UserAssignment;
56  import org.codehaus.plexus.redback.role.RoleManager;
57  import org.codehaus.plexus.redback.role.RoleManagerException;
58  import org.codehaus.plexus.redback.users.User;
59  import org.slf4j.Logger;
60  import org.slf4j.LoggerFactory;
61  
62  /**
63   * ProjectGroupAction:
64   *
65   * @author Jesse McConnell <jmcconnell@apache.org>
66   * @version $Id: ProjectGroupAction.java 1101669 2011-05-10 22:46:21Z ctan $
67   * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="projectGroup"
68   */
69  public class ProjectGroupAction
70      extends ContinuumConfirmAction
71  {
72      private static final Logger logger = LoggerFactory.getLogger( ProjectGroupAction.class );
73  
74      private static final Map<String, String> FILTER_CRITERIA = new HashMap<String, String>();
75  
76      static
77      {
78          FILTER_CRITERIA.put( "username", "Username contains" );
79          FILTER_CRITERIA.put( "fullName", "Name contains" );
80          FILTER_CRITERIA.put( "email", "Email contains" );
81      }
82  
83      /**
84       * @plexus.requirement role-hint="cached"
85       */
86      private RBACManager rbac;
87  
88      /**
89       * @plexus.requirement role-hint="default"
90       */
91      private RoleManager roleManager;
92  
93      /**
94       * @plexus.requirement role-hint="parallel"
95       */
96      private BuildsManager parallelBuildsManager;
97  
98      private int projectGroupId;
99  
100     private ProjectGroup projectGroup;
101 
102     private String name;
103 
104     private String description;
105 
106     private Map projects = new HashMap();
107 
108     private Map<Integer, String> projectGroups = new HashMap<Integer, String>();
109 
110     private boolean projectInCOQueue = false;
111 
112     private Collection<Project> projectList;
113 
114     private List<ProjectGroupUserBean> projectGroupUsers;
115 
116     private String filterProperty;
117 
118     private String filterKey;
119 
120     //Default order is by username
121     private String sorterProperty = "username";
122 
123     private boolean ascending = true;
124 
125     private Collection groupProjects;
126 
127     private int releaseProjectId;
128 
129     private Map<String, Integer> buildDefinitions;
130 
131     private int buildDefinitionId;
132 
133     private boolean fromSummaryPage = false;
134 
135     private String preferredExecutor = "maven2";
136 
137     private String url;
138 
139     private int repositoryId;
140 
141     private List<LocalRepository> repositories;
142 
143     private boolean disabledRepositories = true;
144 
145     private List<ProjectScmRoot> projectScmRoots;
146 
147     public void prepare()
148         throws Exception
149     {
150         super.prepare();
151     
152         repositories = getContinuum().getRepositoryService().getAllLocalRepositories();
153     }
154     
155     public String summary()
156         throws ContinuumException
157     {
158         try
159         {
160             checkViewProjectGroupAuthorization( getProjectGroupName() );
161         }
162         catch ( AuthorizationRequiredException authzE )
163         {
164             addActionError( authzE.getMessage() );
165             return REQUIRES_AUTHORIZATION;
166         }
167         catch ( ContinuumException e )
168         {
169             addActionError( getText( "projectGroup.invalid.id", "Invalid Project Group Id: " + projectGroupId,
170                                      Integer.toString( projectGroupId ) ) );
171             return "to_summary_page";
172         }
173 
174         projectGroup = getContinuum().getProjectGroupWithProjects( projectGroupId );
175 
176         List<BuildDefinition> projectGroupBuildDefs =
177             getContinuum().getBuildDefinitionsForProjectGroup( projectGroupId );
178 
179         if ( projectGroupBuildDefs != null )
180         {
181             this.buildDefinitions = new LinkedHashMap<String, Integer>( projectGroupBuildDefs.size() );
182             for ( BuildDefinition buildDefinition : projectGroupBuildDefs )
183             {
184 
185                 if ( !buildDefinition.isDefaultForProject() )
186                 {
187                     String key = StringUtils.isEmpty( buildDefinition.getDescription() ) ? buildDefinition.getGoals()
188                         : buildDefinition.getDescription();
189                     buildDefinitions.put( key, buildDefinition.getId() );
190                 }
191             }
192         }
193         else
194         {
195             this.buildDefinitions = Collections.EMPTY_MAP;
196         }
197 
198         if ( projectGroup != null )
199         {   
200             if ( projectGroup.getProjects() != null && projectGroup.getProjects().size() > 0 )
201             {
202                 int nbMaven2Projects = 0;
203                 int nbMaven1Projects = 0;
204                 int nbAntProjects = 0;
205                 int nbShellProjects = 0;
206 
207                 Project rootProject = ( getContinuum().getProjectsInBuildOrder(
208                     getContinuum().getProjectsInGroupWithDependencies( projectGroupId ) ) ).get( 0 );
209                 if ( "maven2".equals( rootProject.getExecutorId() ) || "maven-1".equals( rootProject.getExecutorId() ) )
210                 {
211                     url = rootProject.getUrl();
212                 }
213 
214                 for ( Object o : projectGroup.getProjects() )
215                 {
216                     Project p = (Project) o;
217                     if ( "maven2".equals( p.getExecutorId() ) )
218                     {
219                         nbMaven2Projects += 1;
220                     }
221                     else if ( "maven-1".equals( p.getExecutorId() ) )
222                     {
223                         nbMaven1Projects += 1;
224                     }
225                     else if ( "ant".equals( p.getExecutorId() ) )
226                     {
227                         nbAntProjects += 1;
228                     }
229                     else if ( "shell".equals( p.getExecutorId() ) )
230                     {
231                         nbShellProjects += 1;
232                     }
233                 }
234 
235                 int nbActualPreferredProject = nbMaven2Projects;
236                 if ( nbMaven1Projects > nbActualPreferredProject )
237                 {
238                     preferredExecutor = "maven-1";
239                     nbActualPreferredProject = nbMaven1Projects;
240                 }
241                 if ( nbAntProjects > nbActualPreferredProject )
242                 {
243                     preferredExecutor = "ant";
244                     nbActualPreferredProject = nbAntProjects;
245                 }
246                 if ( nbShellProjects > nbActualPreferredProject )
247                 {
248                     preferredExecutor = "shell";
249                 }
250             }
251 
252             projectScmRoots = getContinuum().getProjectScmRootByProjectGroup( projectGroup.getId() );
253         }
254 
255         return SUCCESS;
256     }
257 
258     public String members()
259         throws ContinuumException
260     {
261         try
262         {
263             checkViewProjectGroupAuthorization( getProjectGroupName() );
264         }
265         catch ( AuthorizationRequiredException authzE )
266         {
267             addActionError( authzE.getMessage() );
268             return REQUIRES_AUTHORIZATION;
269         }
270 
271         projectGroup = getContinuum().getProjectGroupWithProjects( projectGroupId );
272 
273         groupProjects = projectGroup.getProjects();
274 
275         populateProjectGroupUsers( projectGroup );
276 
277         return SUCCESS;
278     }
279 
280     public Collection getGroupProjects()
281         throws ContinuumException
282     {
283         return groupProjects;
284     }
285 
286     public String buildDefinitions()
287         throws ContinuumException
288     {
289         return summary();
290     }
291 
292     public String notifiers()
293         throws ContinuumException
294     {
295         return summary();
296     }
297 
298     public String remove()
299         throws ContinuumException
300     {
301         try
302         {
303             checkRemoveProjectGroupAuthorization( getProjectGroupName() );
304         }
305         catch ( AuthorizationRequiredException authzE )
306         {
307             addActionError( authzE.getMessage() );
308             return REQUIRES_AUTHORIZATION;
309         }
310 
311         try
312         {
313             getContinuum().removeProjectGroup( projectGroupId );
314         }
315         catch ( ContinuumException e )
316         {
317             logger.error( "Error while removing project group with id " + projectGroupId, e );
318             addActionError( getText( "projectGroup.delete.error", "Unable to remove project group",
319                                      Integer.toString( projectGroupId ) ) );
320         }
321 
322         AuditLog event = new AuditLog( "Project Group id=" + projectGroupId, AuditLogConstants.REMOVE_PROJECT_GROUP );
323         event.setCategory( AuditLogConstants.PROJECT );
324         event.setCurrentUser( getPrincipal() );
325         event.log();
326 
327         return SUCCESS;
328     }
329 
330     public String confirmRemove()
331         throws ContinuumException
332     {
333         try
334         {
335             checkRemoveProjectGroupAuthorization( getProjectGroupName() );
336         }
337         catch ( AuthorizationRequiredException authzE )
338         {
339             addActionError( authzE.getMessage() );
340             return REQUIRES_AUTHORIZATION;
341         }
342 
343         name = getProjectGroupName();
344         return CONFIRM;
345     }
346 
347     private void initialize()
348         throws ContinuumException
349     {
350         try
351         {
352             checkManageLocalRepositoriesAuthorization();
353             disabledRepositories = false;
354         }
355         catch ( AuthorizationRequiredException authzE )
356         {
357             // do nothing
358         }
359 
360         projectGroup = getContinuum().getProjectGroupWithProjects( projectGroupId );
361 
362         projectList = projectGroup.getProjects();
363 
364         if ( projectList != null )
365         {
366             for ( Project p : projectList )
367             {
368                 try
369                 {
370                     if ( parallelBuildsManager.isInAnyCheckoutQueue( p.getId() ) )
371                     {
372                         projectInCOQueue = true;
373                     }
374                 }
375                 catch ( BuildManagerException e )
376                 {
377                     throw new ContinuumException( e.getMessage(), e );
378                 }
379                 projects.put( p, p.getProjectGroup().getId() );
380             }
381         }
382 
383         for ( ProjectGroup pg : getContinuum().getAllProjectGroups() )
384         {
385             if ( isAuthorized( projectGroup.getName() ) )
386             {
387                 projectGroups.put( pg.getId(), pg.getName() );
388             }
389         }
390         repositories = getContinuum().getRepositoryService().getAllLocalRepositories();
391     }
392 
393     public String edit()
394         throws ContinuumException
395     {
396         try
397         {
398             checkModifyProjectGroupAuthorization( getProjectGroupName() );
399         }
400         catch ( AuthorizationRequiredException authzE )
401         {
402             addActionError( authzE.getMessage() );
403             return REQUIRES_AUTHORIZATION;
404         }
405 
406         initialize();
407 
408         name = projectGroup.getName();
409 
410         description = projectGroup.getDescription();
411 
412         projectList = projectGroup.getProjects();
413 
414         if ( projectGroup.getLocalRepository() != null )
415         {
416             repositoryId = projectGroup.getLocalRepository().getId();
417         }
418         else
419         {
420             repositoryId = -1;
421         }
422 
423         Collection<Project> projList = getContinuum().getProjectsInGroupWithDependencies( projectGroup.getId() );
424         if ( projList != null && projList.size() > 0 )
425         {
426             Project rootProject = ( getContinuum().getProjectsInBuildOrder( projList ) ).get( 0 );
427 
428             if ( rootProject != null )
429             {
430                 setUrl( rootProject.getUrl() );
431             }
432         }
433         return SUCCESS;
434     }
435 
436     public String save()
437         throws Exception
438     {
439         try
440         {
441             checkModifyProjectGroupAuthorization( getProjectGroupName() );
442         }
443         catch ( AuthorizationRequiredException authzE )
444         {
445             addActionError( authzE.getMessage() );
446             return REQUIRES_AUTHORIZATION;
447         }
448 
449         for ( ProjectGroup projectGroup : getContinuum().getAllProjectGroups() )
450         {
451             if ( name.equals( projectGroup.getName() ) && projectGroup.getId() != projectGroupId )
452             {
453                 addActionError( getText( "projectGroup.error.name.already.exists" ) );
454             }
455         }
456 
457         if ( hasActionErrors() )
458         {
459             initialize();
460             return INPUT;
461         }
462 
463         projectGroup = getContinuum().getProjectGroupWithProjects( projectGroupId );
464 
465         // need to administer roles since they are based off of this
466         // todo convert everything like to work off of string keys
467         if ( !name.equals( projectGroup.getName() ) )
468         {
469             // CONTINUUM-1502
470             name = name.trim();
471             try
472             {
473                 roleManager.updateRole( "project-administrator", projectGroup.getName(), name );
474                 roleManager.updateRole( "project-developer", projectGroup.getName(), name );
475                 roleManager.updateRole( "project-user", projectGroup.getName(), name );
476 
477                 projectGroup.setName( name );
478             }
479             catch ( RoleManagerException e )
480             {
481                 throw new ContinuumException( "unable to rename the project group", e );
482             }
483 
484         }
485 
486         projectGroup.setDescription( StringEscapeUtils.escapeXml( StringEscapeUtils.unescapeXml( description ) ) );
487 
488         // [CONTINUUM-2228]. In select field can't select empty values.
489         if ( repositoryId > 0 )
490         {
491             LocalRepository repository = getContinuum().getRepositoryService().getLocalRepository( repositoryId );
492             projectGroup.setLocalRepository( repository );
493         }
494 
495         getContinuum().updateProjectGroup( projectGroup );
496 
497         Collection<Project> projectList = getContinuum().getProjectsInGroupWithDependencies( projectGroupId );
498         if ( projectList != null && projectList.size() > 0 )
499         {
500             Project rootProject = ( getContinuum().getProjectsInBuildOrder( projectList ) ).get( 0 );
501 
502             rootProject.setUrl( url );
503 
504             getContinuum().updateProject( rootProject );
505         }
506 
507         Iterator keys = projects.keySet().iterator();
508         while ( keys.hasNext() )
509         {
510             String key = (String) keys.next();
511 
512             String[] id = (String[]) projects.get( key );
513 
514             int projectId = Integer.parseInt( key );
515 
516             Project project = null;
517             Iterator i = projectGroup.getProjects().iterator();
518             while ( i.hasNext() )
519             {
520                 project = (Project) i.next();
521                 if ( projectId == project.getId() )
522                 {
523                     break;
524                 }
525             }
526 
527             ProjectGroup newProjectGroup = getContinuum().getProjectGroupWithProjects( new Integer( id[0] ) );
528 
529             if ( newProjectGroup.getId() != projectGroup.getId() && isAuthorized( newProjectGroup.getName() ) )
530             {
531                 logger.info( "Moving project " + project.getName() + " to project group " + newProjectGroup.getName() );
532                 project.setProjectGroup( newProjectGroup );
533 
534                 // CONTINUUM-1512
535                 Collection<BuildResult> results = getContinuum().getBuildResultsForProject( project.getId() );
536                 for ( BuildResult br : results )
537                 {
538                     getContinuum().removeBuildResult( br.getId() );
539                 }
540 
541                 getContinuum().updateProject( project );
542             }
543         }
544 
545         AuditLog event = new AuditLog( "Project Group id=" + projectGroupId, AuditLogConstants.MODIFY_PROJECT_GROUP );
546         event.setCategory( AuditLogConstants.PROJECT );
547         event.setCurrentUser( getPrincipal() );
548         event.log();
549 
550         return SUCCESS;
551     }
552 
553     public String build()
554         throws ContinuumException
555     {
556         try
557         {
558             checkBuildProjectGroupAuthorization( getProjectGroupName() );
559         }
560         catch ( AuthorizationRequiredException authzE )
561         {
562             addActionError( authzE.getMessage() );
563             return REQUIRES_AUTHORIZATION;
564         }
565 
566         if ( this.getBuildDefinitionId() == -1 )
567         {
568             getContinuum().buildProjectGroup( projectGroupId );
569         }
570         else
571         {
572             getContinuum().buildProjectGroupWithBuildDefinition( projectGroupId, buildDefinitionId );
573         }
574 
575         AuditLog event = new AuditLog( "Project Group id=" + projectGroupId, AuditLogConstants.FORCE_BUILD );
576         event.setCategory( AuditLogConstants.PROJECT );
577         event.setCurrentUser( getPrincipal() );
578         event.log();
579 
580         if ( this.isFromSummaryPage() )
581         {
582             return "to_summary_page";
583         }
584         else
585         {
586             return SUCCESS;
587         }
588     }
589 
590     public String release()
591         throws ContinuumException
592     {
593         try
594         {
595             checkBuildProjectGroupAuthorization( getProjectGroupName() );
596         }
597         catch ( AuthorizationRequiredException authzE )
598         {
599             addActionError( authzE.getMessage() );
600             return REQUIRES_AUTHORIZATION;
601         }
602 
603         // get the parent of the group by finding the parent project
604         // i.e., the project that doesn't have a parent, or it's parent is not in the group.
605 
606         Project parent = null;
607 
608         boolean allBuildsOk = true;
609 
610         boolean allMavenTwo = true;
611 
612         projectList = getContinuum().getProjectsInGroupWithDependencies( projectGroupId );
613 
614         if ( projectList != null )
615         {
616             for ( Project p : projectList )
617             {
618                 if ( p.getState() != ContinuumProjectState.OK )
619                 {
620                     allBuildsOk = false;
621                 }
622 
623                 if ( ( p.getParent() == null ) || ( !isParentInProjectGroup( p.getParent(), projectList ) ) )
624                 {
625                     if ( parent == null )
626                     {
627                         parent = p;
628                     }
629                     else
630                     {
631                         // currently, we have no provisions for releasing 2 or more parents
632                         // at the same time, this will be implemented in the future
633                         addActionError( getText( "projectGroup.release.error.severalParentProjects" ) );
634                         return INPUT;
635                     }
636                 }
637 
638                 if ( !"maven2".equals( p.getExecutorId() ) )
639                 {
640                     allMavenTwo = false;
641                 }
642             }
643         }
644 
645         if ( parent == null )
646         {
647             addActionError( getText( "projectGroup.release.error.emptyGroup" ) );
648             return INPUT;
649         }
650 
651         releaseProjectId = parent.getId();
652 
653         if ( allBuildsOk && allMavenTwo )
654         {
655             return SUCCESS;
656         }
657         else
658         {
659             addActionError( getText( "projectGroup.release.error.projectNotInSuccess" ) );
660             return INPUT;
661         }
662     }
663 
664     private boolean isParentInProjectGroup( ProjectDependency parent, Collection<Project> projectsInGroup )
665         throws ContinuumException
666     {
667         boolean result = false;
668 
669         for ( Project project : projectsInGroup )
670         {
671             if ( parent != null )
672             {
673                 if ( ( project.getArtifactId().equals( parent.getArtifactId() ) ) &&
674                     ( project.getGroupId().equals( parent.getGroupId() ) ) &&
675                     ( project.getVersion().equals( parent.getVersion() ) ) )
676                 {
677                     result = true;
678                 }
679             }
680         }
681 
682         return result;
683     }
684 
685     private void populateProjectGroupUsers( ProjectGroup group )
686     {
687         List<User> users = new ArrayList<User>();
688 
689         try
690         {
691             List<Role> roles = rbac.getAllRoles();
692             List<String> roleNames = new ArrayList<String>();
693             for ( Role r : roles )
694             {
695                 String projectGroupName = StringUtils.substringAfter( r.getName(), "-" ).trim();
696 
697                 if ( projectGroupName.equals( group.getName() ) )
698                 {
699                     roleNames.add( r.getName() );
700                 }
701             }
702             List<UserAssignment> userAssignments = rbac.getUserAssignmentsForRoles( roleNames );
703             for ( UserAssignment ua : userAssignments )
704             {
705                 User u = getSecuritySystem().getUserManager().findUser( ua.getPrincipal() );
706                 if ( u != null )
707                 {
708                     users.add( u );
709                 }
710             }
711         }
712         catch ( Exception e )
713         {
714             logger.error( "Can't get the users list", e );
715         }
716 
717         if ( StringUtils.isNotBlank( filterKey ) )
718         {
719             users = findUsers( users, filterProperty, filterKey );
720         }
721         if ( StringUtils.isNotBlank( sorterProperty ) )
722         {
723             sortUsers( users, sorterProperty, ascending );
724         }
725 
726         projectGroupUsers = new ArrayList<ProjectGroupUserBean>();
727 
728         if ( users == null )
729         {
730             return;
731         }
732 
733         for ( User user : users )
734         {
735             ProjectGroupUserBean pgUser = new ProjectGroupUserBean();
736 
737             pgUser.setUser( user );
738 
739             pgUser.setProjectGroup( group );
740 
741             try
742             {
743                 Collection<Role> effectiveRoles = rbac.getEffectivelyAssignedRoles( user.getUsername() );
744 
745                 for ( Role role : effectiveRoles )
746                 {
747                     if ( role.getName().indexOf( projectGroup.getName() ) > -1 )
748                     {
749                         pgUser.setRoles( effectiveRoles );
750                         projectGroupUsers.add( pgUser );
751                         break;
752                     }
753                 }
754             }
755             catch ( RbacObjectNotFoundException e )
756             {
757                 pgUser.setRoles( Collections.EMPTY_LIST );
758             }
759             catch ( RbacManagerException e )
760             {
761                 pgUser.setRoles( Collections.EMPTY_LIST );
762             }
763         }
764     }
765 
766     private List<User> findUsers( List<User> users, String searchProperty, String searchKey )
767     {
768         List<User> userList = new ArrayList<User>();
769         for ( User user : users )
770         {
771             if ( "username".equals( searchProperty ) )
772             {
773                 String username = user.getUsername();
774                 if ( username != null )
775                 {
776                     if ( username.toLowerCase().indexOf( searchKey.toLowerCase() ) >= 0 )
777                     {
778                         userList.add( user );
779                     }
780                 }
781             }
782             else if ( "fullName".equals( searchProperty ) )
783             {
784                 String fullname = user.getFullName();
785                 if ( fullname != null )
786                 {
787                     if ( fullname.toLowerCase().indexOf( searchKey.toLowerCase() ) >= 0 )
788                     {
789                         userList.add( user );
790                     }
791                 }
792             }
793             else if ( "email".equals( searchProperty ) )
794             {
795                 String email = user.getEmail();
796                 if ( email != null )
797                 {
798                     if ( email.toLowerCase().indexOf( searchKey.toLowerCase() ) >= 0 )
799                     {
800                         userList.add( user );
801                     }
802                 }
803             }
804         }
805 
806         return userList;
807     }
808 
809     private void sortUsers( List<User> userList, final String sorterProperty, final boolean orderAscending )
810     {
811         Collections.sort( userList, new Comparator<User>()
812         {
813             public int compare( User o1, User o2 )
814             {
815                 String value1, value2;
816                 if ( "fullName".equals( sorterProperty ) )
817                 {
818                     value1 = o1.getFullName();
819                     value2 = o2.getFullName();
820                 }
821                 else if ( "email".equals( sorterProperty ) )
822                 {
823                     value1 = o1.getEmail();
824                     value2 = o2.getEmail();
825                 }
826                 else
827                 {
828                     value1 = o1.getUsername();
829                     value2 = o2.getUsername();
830                 }
831                 if ( orderAscending )
832                 {
833                     return ComparatorUtils.nullLowComparator( null ).compare( value1, value2 );
834                 }
835                 return ComparatorUtils.nullLowComparator( null ).compare( value2, value1 );
836             }
837         } );
838     }
839 
840     public int getProjectGroupId()
841     {
842         return projectGroupId;
843     }
844 
845     public void setProjectGroupId( int projectGroupId )
846     {
847         this.projectGroupId = projectGroupId;
848     }
849 
850     public ProjectGroup getProjectGroup()
851     {
852         return projectGroup;
853     }
854 
855     public void setProjectGroup( ProjectGroup projectGroup )
856     {
857         this.projectGroup = projectGroup;
858     }
859 
860     public String getDescription()
861     {
862         return description;
863     }
864 
865     public void setDescription( String description )
866     {
867         this.description = description;
868     }
869 
870     public String getName()
871     {
872         return name;
873     }
874 
875     public void setName( String name )
876     {
877         this.name = name;
878     }
879 
880     public Map getProjects()
881     {
882         return projects;
883     }
884 
885     public void setProjects( Map projects )
886     {
887         this.projects = projects;
888     }
889 
890     public Map<Integer, String> getProjectGroups()
891     {
892         return projectGroups;
893     }
894 
895     public void setProjectGroups( Map<Integer, String> projectGroups )
896     {
897         this.projectGroups = projectGroups;
898     }
899 
900     public boolean isProjectInCOQueue()
901     {
902         return projectInCOQueue;
903     }
904 
905     public void setProjectInCOQueue( boolean projectInQueue )
906     {
907         this.projectInCOQueue = projectInQueue;
908     }
909 
910     public Collection<Project> getProjectList()
911     {
912         return projectList;
913     }
914 
915     public List<ProjectGroupUserBean> getProjectGroupUsers()
916     {
917         return projectGroupUsers;
918     }
919 
920     public boolean isAscending()
921     {
922         return ascending;
923     }
924 
925     public void setAscending( boolean ascending )
926     {
927         this.ascending = ascending;
928     }
929 
930     public String getFilterKey()
931     {
932         return filterKey;
933     }
934 
935     public void setFilterKey( String filterKey )
936     {
937         this.filterKey = filterKey;
938     }
939 
940     public String getFilterProperty()
941     {
942         return filterProperty;
943     }
944 
945     public void setFilterProperty( String filterProperty )
946     {
947         this.filterProperty = filterProperty;
948     }
949 
950     public Map<String, String> getCriteria()
951     {
952         return FILTER_CRITERIA;
953     }
954 
955     public void setReleaseProjectId( int releaseProjectId )
956     {
957         this.releaseProjectId = releaseProjectId;
958     }
959 
960     public int getReleaseProjectId()
961     {
962         return this.releaseProjectId;
963     }
964 
965     public ProjectGroup getProjectGroup( int projectGroupId )
966         throws ContinuumException
967     {
968         if ( projectGroup == null )
969         {
970             projectGroup = getContinuum().getProjectGroup( projectGroupId );
971         }
972         else
973         {
974             if ( projectGroup.getId() != projectGroupId )
975             {
976                 projectGroup = getContinuum().getProjectGroup( projectGroupId );
977             }
978         }
979 
980         return projectGroup;
981     }
982 
983     public String getProjectGroupName()
984         throws ContinuumException
985     {
986 
987         return getProjectGroup( projectGroupId ).getName();
988     }
989 
990     public Map<String, Integer> getBuildDefinitions()
991     {
992         return buildDefinitions;
993     }
994 
995     public void setBuildDefinitions( Map<String, Integer> buildDefinitions )
996     {
997         this.buildDefinitions = buildDefinitions;
998     }
999 
1000     public int getBuildDefinitionId()
1001     {
1002         return buildDefinitionId;
1003     }
1004 
1005     public void setBuildDefinitionId( int buildDefinitionId )
1006     {
1007         this.buildDefinitionId = buildDefinitionId;
1008     }
1009 
1010     public boolean isFromSummaryPage()
1011     {
1012         return fromSummaryPage;
1013     }
1014 
1015     public void setFromSummaryPage( boolean fromSummaryPage )
1016     {
1017         this.fromSummaryPage = fromSummaryPage;
1018     }
1019 
1020     public String getPreferredExecutor()
1021     {
1022         return preferredExecutor;
1023     }
1024 
1025     public String getUrl()
1026     {
1027         return url;
1028     }
1029 
1030     public void setUrl( String url )
1031     {
1032         this.url = url;
1033     }
1034 
1035     public int getRepositoryId()
1036     {
1037         return repositoryId;
1038     }
1039 
1040     public void setRepositoryId( int repositoryId )
1041     {
1042         this.repositoryId = repositoryId;
1043     }
1044 
1045     public List<LocalRepository> getRepositories()
1046     {
1047         return repositories;
1048     }
1049 
1050     public void setRepositories( List<LocalRepository> repositories )
1051     {
1052         this.repositories = repositories;
1053     }
1054 
1055     public boolean isDisabledRepositories()
1056     {
1057         return disabledRepositories;
1058     }
1059 
1060     public void setDisabledRepositories( boolean disabledRepositories )
1061     {
1062         this.disabledRepositories = disabledRepositories;
1063     }
1064 
1065     public List<ProjectScmRoot> getProjectScmRoots()
1066     {
1067         return projectScmRoots;
1068     }
1069 
1070     public void setProjectScmRoots( List<ProjectScmRoot> projectScmRoots )
1071     {
1072         this.projectScmRoots = projectScmRoots;
1073     }
1074 
1075     private boolean isAuthorized( String projectGroupName )
1076     {
1077         try
1078         {
1079             checkAddProjectToGroupAuthorization( projectGroupName );
1080             return true;
1081         }
1082         catch ( AuthorizationRequiredException authzE )
1083         {
1084             return false;
1085         }
1086     }
1087 
1088     public String getSorterProperty()
1089     {
1090         return sorterProperty;
1091     }
1092 
1093     public void setSorterProperty( String sorterProperty )
1094     {
1095         this.sorterProperty = sorterProperty;
1096     }
1097 }