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