001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.service.impl;
016    
017    import com.liferay.portal.NoSuchGroupException;
018    import com.liferay.portal.kernel.dao.orm.QueryUtil;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.staging.StagingUtil;
021    import com.liferay.portal.kernel.util.ArrayUtil;
022    import com.liferay.portal.kernel.util.ListUtil;
023    import com.liferay.portal.kernel.util.MapUtil;
024    import com.liferay.portal.kernel.util.OrderByComparator;
025    import com.liferay.portal.kernel.util.UnicodeProperties;
026    import com.liferay.portal.model.Group;
027    import com.liferay.portal.model.GroupConstants;
028    import com.liferay.portal.model.Organization;
029    import com.liferay.portal.model.Portlet;
030    import com.liferay.portal.model.User;
031    import com.liferay.portal.model.UserGroup;
032    import com.liferay.portal.security.auth.PrincipalException;
033    import com.liferay.portal.security.membershippolicy.SiteMembershipPolicyUtil;
034    import com.liferay.portal.security.permission.ActionKeys;
035    import com.liferay.portal.security.permission.PermissionChecker;
036    import com.liferay.portal.security.permission.PermissionCheckerFactoryUtil;
037    import com.liferay.portal.service.ServiceContext;
038    import com.liferay.portal.service.base.GroupServiceBaseImpl;
039    import com.liferay.portal.service.permission.GroupPermissionUtil;
040    import com.liferay.portal.service.permission.PortalPermissionUtil;
041    import com.liferay.portal.service.permission.PortletPermissionUtil;
042    import com.liferay.portal.service.permission.RolePermissionUtil;
043    import com.liferay.portal.service.permission.UserPermissionUtil;
044    import com.liferay.portal.util.PropsValues;
045    import com.liferay.portlet.asset.model.AssetCategory;
046    import com.liferay.portlet.asset.model.AssetTag;
047    import com.liferay.portlet.expando.model.ExpandoBridge;
048    
049    import java.io.Serializable;
050    
051    import java.util.ArrayList;
052    import java.util.Collection;
053    import java.util.Collections;
054    import java.util.Iterator;
055    import java.util.LinkedHashMap;
056    import java.util.LinkedHashSet;
057    import java.util.List;
058    import java.util.Map;
059    import java.util.Set;
060    
061    /**
062     * Provides the remote service for accessing, adding, deleting, and updating
063     * groups. Its methods include permission checks. Groups are mostly used in
064     * Liferay as a resource container for permissioning and content scoping
065     * purposes.
066     *
067     * @author Brian Wing Shun Chan
068     * @see    com.liferay.portal.service.impl.GroupLocalServiceImpl
069     */
070    public class GroupServiceImpl extends GroupServiceBaseImpl {
071    
072            @Override
073            public Group addGroup(
074                            long parentGroupId, long liveGroupId, String name,
075                            String description, int type, boolean manualMembership,
076                            int membershipRestriction, String friendlyURL, boolean site,
077                            boolean inheritContent, boolean active,
078                            ServiceContext serviceContext)
079                    throws PortalException {
080    
081                    if (parentGroupId == GroupConstants.DEFAULT_PARENT_GROUP_ID) {
082                            PortalPermissionUtil.check(
083                                    getPermissionChecker(), ActionKeys.ADD_COMMUNITY);
084                    }
085                    else {
086                            GroupPermissionUtil.check(
087                                    getPermissionChecker(), parentGroupId,
088                                    ActionKeys.ADD_COMMUNITY);
089                    }
090    
091                    Group group = groupLocalService.addGroup(
092                            getUserId(), parentGroupId, null, 0, liveGroupId, name, description,
093                            type, manualMembership, membershipRestriction, friendlyURL, site,
094                            inheritContent, active, serviceContext);
095    
096                    if (site) {
097                            SiteMembershipPolicyUtil.verifyPolicy(group);
098                    }
099    
100                    return group;
101            }
102    
103            /**
104             * Adds a group.
105             *
106             * @param  parentGroupId the primary key of the parent group
107             * @param  liveGroupId the primary key of the live group
108             * @param  name the entity's name
109             * @param  description the group's description (optionally
110             *         <code>null</code>)
111             * @param  type the group's type. For more information see {@link
112             *         GroupConstants}.
113             * @param  manualMembership whether manual membership is allowed for the
114             *         group
115             * @param  membershipRestriction the group's membership restriction. For
116             *         more information see {@link GroupConstants}.
117             * @param  friendlyURL the group's friendlyURL (optionally
118             *         <code>null</code>)
119             * @param  site whether the group is to be associated with a main site
120             * @param  active whether the group is active
121             * @param  serviceContext the service context to be applied (optionally
122             *         <code>null</code>). Can set the asset category IDs and asset tag
123             *         names for the group, and can set whether the group is for staging
124             * @return the group
125             * @throws PortalException if the user did not have permission to add the
126             *         group, if a creator could not be found, if the group's
127             *         information was invalid, if a layout could not be found, or if a
128             *         valid friendly URL could not be created for the group
129             */
130            @Override
131            public Group addGroup(
132                            long parentGroupId, long liveGroupId, String name,
133                            String description, int type, boolean manualMembership,
134                            int membershipRestriction, String friendlyURL, boolean site,
135                            boolean active, ServiceContext serviceContext)
136                    throws PortalException {
137    
138                    return addGroup(
139                            parentGroupId, liveGroupId, name, description, type,
140                            manualMembership, membershipRestriction, friendlyURL, site, false,
141                            active, serviceContext);
142            }
143    
144            /**
145             * Adds the group using the group default live group ID.
146             *
147             * @param      parentGroupId the primary key of the parent group
148             * @param      name the entity's name
149             * @param      description the group's description (optionally
150             *             <code>null</code>)
151             * @param      type the group's type. For more information see {@link
152             *             GroupConstants}.
153             * @param      friendlyURL the group's friendlyURL
154             * @param      site whether the group is to be associated with a main site
155             * @param      active whether the group is active
156             * @param      serviceContext the service context to be applied (optionally
157             *             <code>null</code>). Can set asset category IDs and asset tag
158             *             names for the group, and can set whether the group is for
159             *             staging
160             * @return     the group
161             * @throws     PortalException if the user did not have permission to add
162             *             the group, if a creator could not be found, if the group's
163             *             information was invalid, if a layout could not be found, or
164             *             if a valid friendly URL could not be created for the group
165             * @deprecated As of 6.2.0, replaced by {@link #addGroup(long, long, String,
166             *             String, int, boolean, int, String, boolean, boolean,
167             *             ServiceContext)}
168             */
169            @Deprecated
170            @Override
171            public Group addGroup(
172                            long parentGroupId, String name, String description, int type,
173                            String friendlyURL, boolean site, boolean active,
174                            ServiceContext serviceContext)
175                    throws PortalException {
176    
177                    return addGroup(
178                            parentGroupId, GroupConstants.DEFAULT_LIVE_GROUP_ID, name,
179                            description, type, true,
180                            GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION, friendlyURL, site,
181                            active, serviceContext);
182            }
183    
184            /**
185             * @deprecated As of 6.2.0, replaced by {@link #addGroup(long, String,
186             *             String, int, String, boolean, boolean, ServiceContext)}
187             */
188            @Deprecated
189            @Override
190            public Group addGroup(
191                            String name, String description, int type, String friendlyURL,
192                            boolean site, boolean active, ServiceContext serviceContext)
193                    throws PortalException {
194    
195                    return addGroup(
196                            GroupConstants.DEFAULT_PARENT_GROUP_ID, name, description, type,
197                            friendlyURL, site, active, serviceContext);
198            }
199    
200            /**
201             * Adds the groups to the role.
202             *
203             * @param  roleId the primary key of the role
204             * @param  groupIds the primary keys of the groups
205             * @throws PortalException if the user did not have permission to update the
206             *         role
207             */
208            @Override
209            public void addRoleGroups(long roleId, long[] groupIds)
210                    throws PortalException {
211    
212                    RolePermissionUtil.check(
213                            getPermissionChecker(), roleId, ActionKeys.UPDATE);
214    
215                    groupLocalService.addRoleGroups(roleId, groupIds);
216            }
217    
218            /**
219             * Checks that the current user is permitted to use the group for Remote
220             * Staging.
221             *
222             * @param  groupId the primary key of the group
223             * @throws PortalException if a group with the primary key could not be
224             *         found, if the current user did not have permission to view the
225             *         group, or if the group's company was different from the current
226             *         user's company
227             */
228            @Override
229            public void checkRemoteStagingGroup(long groupId) throws PortalException {
230                    Group group = getGroup(groupId);
231    
232                    PermissionChecker permissionChecker = getPermissionChecker();
233    
234                    if (group.getCompanyId() != permissionChecker.getCompanyId()) {
235                            throw new NoSuchGroupException(
236                                    "Group " + groupId + " does not belong in company " +
237                                            permissionChecker.getCompanyId());
238                    }
239            }
240    
241            /**
242             * Deletes the group.
243             *
244             * <p>
245             * The group is unstaged and its assets and resources including layouts,
246             * membership requests, subscriptions, teams, blogs, bookmarks, calendar
247             * events, image gallery, journals, message boards, polls, shopping related
248             * entities, software catalog, and wikis are also deleted.
249             * </p>
250             *
251             * @param  groupId the primary key of the group
252             * @throws PortalException if the user did not have permission to delete the
253             *         group or its assets or resources, if a group with the primary key
254             *         could not be found, or if the group was a system group
255             */
256            @Override
257            public void deleteGroup(long groupId) throws PortalException {
258                    GroupPermissionUtil.check(
259                            getPermissionChecker(), groupId, ActionKeys.DELETE);
260    
261                    groupLocalService.deleteGroup(groupId);
262            }
263    
264            @Override
265            public void disableStaging(long groupId) throws PortalException {
266                    Group group = groupLocalService.getGroup(groupId);
267    
268                    GroupPermissionUtil.check(
269                            getPermissionChecker(), group, ActionKeys.UPDATE);
270    
271                    groupLocalService.disableStaging(groupId);
272            }
273    
274            @Override
275            public void enableStaging(long groupId) throws PortalException {
276                    Group group = groupLocalService.getGroup(groupId);
277    
278                    GroupPermissionUtil.check(
279                            getPermissionChecker(), group, ActionKeys.UPDATE);
280    
281                    groupLocalService.enableStaging(groupId);
282            }
283    
284            /**
285             * Returns the company group.
286             *
287             * @param  companyId the primary key of the company
288             * @return the group associated with the company
289             * @throws PortalException if a matching group could not be found
290             */
291            @Override
292            public Group getCompanyGroup(long companyId) throws PortalException {
293                    Group group = groupLocalService.getCompanyGroup(companyId);
294    
295                    GroupPermissionUtil.check(
296                            getPermissionChecker(), group, ActionKeys.VIEW);
297    
298                    return group;
299            }
300    
301            /**
302             * Returns the group with the primary key.
303             *
304             * @param  groupId the primary key of the group
305             * @return the group with the primary key
306             * @throws PortalException if a group with the primary key could not be
307             *         found or if the current user did not have permission to view the
308             *         group
309             */
310            @Override
311            public Group getGroup(long groupId) throws PortalException {
312                    Group group = groupLocalService.getGroup(groupId);
313    
314                    GroupPermissionUtil.check(
315                            getPermissionChecker(), group, ActionKeys.VIEW);
316    
317                    return group;
318            }
319    
320            /**
321             * Returns the group with the name.
322             *
323             * @param  companyId the primary key of the company
324             * @param  name the group's name
325             * @return the group with the name
326             * @throws PortalException if a matching group could not be found or if the
327             *         current user did not have permission to view the group
328             */
329            @Override
330            public Group getGroup(long companyId, String name) throws PortalException {
331                    Group group = groupLocalService.getGroup(companyId, name);
332    
333                    GroupPermissionUtil.check(
334                            getPermissionChecker(), group, ActionKeys.VIEW);
335    
336                    return group;
337            }
338    
339            /**
340             * Returns all the groups that are direct children of the parent group.
341             *
342             * @param  companyId the primary key of the company
343             * @param  parentGroupId the primary key of the parent group
344             * @param  site whether the group is to be associated with a main site
345             * @return the matching groups, or <code>null</code> if no matches were
346             *         found
347             * @throws PortalException if the user did not have permission to view the
348             *         group or if a portal exception occurred
349             */
350            @Override
351            public List<Group> getGroups(
352                            long companyId, long parentGroupId, boolean site)
353                    throws PortalException {
354    
355                    return filterGroups(
356                            groupLocalService.getGroups(companyId, parentGroupId, site));
357            }
358    
359            /**
360             * Returns a range of all the site groups for which the user has control
361             * panel access.
362             *
363             * @param  portlets the portlets to manage
364             * @param  max the upper bound of the range of groups to consider (not
365             *         inclusive)
366             * @return the range of site groups for which the user has Control Panel
367             *         access
368             * @throws PortalException if a portal exception occurred
369             */
370            @Override
371            public List<Group> getManageableSiteGroups(
372                            Collection<Portlet> portlets, int max)
373                    throws PortalException {
374    
375                    PermissionChecker permissionChecker = getPermissionChecker();
376    
377                    if (permissionChecker.isCompanyAdmin()) {
378                            LinkedHashMap<String, Object> params =
379                                    new LinkedHashMap<String, Object>();
380    
381                            params.put("site", Boolean.TRUE);
382    
383                            return ListUtil.unique(
384                                    groupLocalService.search(permissionChecker.getCompanyId(), null,
385                                    null, null, params, true, 0, max));
386                    }
387    
388                    Set<Group> groups = new LinkedHashSet<Group>();
389    
390                    List<Group> userSitesGroups = getUserSitesGroups(null, max);
391    
392                    Iterator<Group> itr = userSitesGroups.iterator();
393    
394                    while (itr.hasNext()) {
395                            Group group = itr.next();
396    
397                            if (group.isSite() &&
398                                    PortletPermissionUtil.hasControlPanelAccessPermission(
399                                            permissionChecker, group.getGroupId(), portlets)) {
400    
401                                    groups.add(group);
402                            }
403                    }
404    
405                    return new ArrayList<Group>(groups);
406            }
407    
408            /**
409             * Returns a range of all the site groups for which the user has control
410             * panel access.
411             *
412             * @param      portlets the portlets to manage
413             * @param      max the upper bound of the range of groups to consider (not
414             *             inclusive)
415             * @return     the range of site groups for which the user has Control Panel
416             *             access
417             * @throws     PortalException if a portal exception occurred
418             * @deprecated As of 6.2.0, replaced by {@link
419             *             #getManageableSiteGroups(Collection, int)}
420             */
421            @Deprecated
422            @Override
423            public List<Group> getManageableSites(Collection<Portlet> portlets, int max)
424                    throws PortalException {
425    
426                    return getManageableSiteGroups(portlets, max);
427            }
428    
429            /**
430             * Returns the groups associated with the organizations.
431             *
432             * @param  organizations the organizations
433             * @return the groups associated with the organizations
434             * @throws PortalException if a portal exception occurred
435             */
436            @Override
437            public List<Group> getOrganizationsGroups(List<Organization> organizations)
438                    throws PortalException {
439    
440                    List<Group> groups = groupLocalService.getOrganizationsGroups(
441                            organizations);
442    
443                    return filterGroups(groups);
444            }
445    
446            /**
447             * Returns the group associated with the user.
448             *
449             * @param  companyId the primary key of the company
450             * @param  userId the primary key of the user
451             * @return the group associated with the user
452             * @throws PortalException if a matching group could not be found or if the
453             *         current user did not have permission to view the group
454             */
455            @Override
456            public Group getUserGroup(long companyId, long userId)
457                    throws PortalException {
458    
459                    Group group = groupLocalService.getUserGroup(companyId, userId);
460    
461                    GroupPermissionUtil.check(
462                            getPermissionChecker(), group, ActionKeys.VIEW);
463    
464                    return group;
465            }
466    
467            /**
468             * Returns the groups associated with the user groups.
469             *
470             * @param  userGroups the user groups
471             * @return the groups associated with the user groups
472             * @throws PortalException if any one of the user group's group could not be
473             *         found
474             */
475            @Override
476            public List<Group> getUserGroupsGroups(List<UserGroup> userGroups)
477                    throws PortalException {
478    
479                    List<Group> groups = groupLocalService.getUserGroupsGroups(userGroups);
480    
481                    return filterGroups(groups);
482            }
483    
484            /**
485             * Returns the range of all groups associated with the user's organization
486             * groups, including the ancestors of the organization groups, unless portal
487             * property <code>organizations.membership.strict</code> is set to
488             * <code>true</code>.
489             *
490             * <p>
491             * Useful when paginating results. Returns a maximum of <code>end -
492             * start</code> instances. <code>start</code> and <code>end</code> are not
493             * primary keys, they are indexes in the result set. Thus, <code>0</code>
494             * refers to the first result in the set. Setting both <code>start</code>
495             * and <code>end</code> to {@link
496             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
497             * result set.
498             * </p>
499             *
500             * @param  userId the primary key of the user
501             * @param  start the lower bound of the range of groups to consider
502             * @param  end the upper bound of the range of groups to consider (not
503             *         inclusive)
504             * @return the range of groups associated with the user's organizations
505             * @throws PortalException if a user with the primary key could not be found
506             *         or if another portal exception occurred
507             */
508            @Override
509            public List<Group> getUserOrganizationsGroups(
510                            long userId, int start, int end)
511                    throws PortalException {
512    
513                    List<Group> groups = groupLocalService.getUserOrganizationsGroups(
514                            userId, start, end);
515    
516                    return filterGroups(groups);
517            }
518    
519            /**
520             * @deprecated As of 6.2.0, replaced by {@link #getUserSitesGroups(long,
521             *             String[], boolean, int)}
522             */
523            @Deprecated
524            @Override
525            public List<Group> getUserPlaces(
526                            long userId, String[] classNames, boolean includeControlPanel,
527                            int max)
528                    throws PortalException {
529    
530                    return getUserSitesGroups(userId, classNames, includeControlPanel, max);
531            }
532    
533            /**
534             * Returns the user's groups &quot;sites&quot; associated with the group
535             * entity class names, including the Control Panel group if the user is
536             * permitted to view the Control Panel.
537             *
538             * <ul>
539             * <li>
540             * Class name &quot;User&quot; includes the user's layout set
541             * group.
542             * </li>
543             * <li>
544             * Class name &quot;Organization&quot; includes the user's
545             * immediate organization groups and inherited organization groups.
546             * </li>
547             * <li>
548             * Class name &quot;Group&quot; includes the user's immediate
549             * organization groups and site groups.
550             * </li>
551             * <li>
552             * A <code>classNames</code>
553             * value of <code>null</code> includes the user's layout set group,
554             * organization groups, inherited organization groups, and site groups.
555             * </li>
556             * </ul>
557             *
558             * @param      userId the primary key of the user
559             * @param      classNames the group entity class names (optionally
560             *             <code>null</code>). For more information see {@link
561             *             #getUserSitesGroups(long, String[], int)}.
562             * @param      max the maximum number of groups to return
563             * @return     the user's groups &quot;sites&quot;
564             * @throws     PortalException if a portal exception occurred
565             * @deprecated As of 6.2.0, replaced by {@link #getUserSitesGroups(long,
566             *             String[], int)}
567             */
568            @Deprecated
569            @Override
570            public List<Group> getUserPlaces(long userId, String[] classNames, int max)
571                    throws PortalException {
572    
573                    return getUserSitesGroups(userId, classNames, max);
574            }
575    
576            /**
577             * Returns the guest or current user's groups &quot;sites&quot; associated
578             * with the group entity class names, including the Control Panel group if
579             * the user is permitted to view the Control Panel.
580             *
581             * <ul>
582             * <li>
583             * Class name &quot;User&quot; includes the user's layout set
584             * group.
585             * </li>
586             * <li>
587             * Class name &quot;Organization&quot; includes the user's
588             * immediate organization groups and inherited organization groups.
589             * </li>
590             * <li>
591             * Class name &quot;Group&quot; includes the user's immediate
592             * organization groups and site groups.
593             * </li>
594             * <li>
595             * A <code>classNames</code>
596             * value of <code>null</code> includes the user's layout set group,
597             * organization groups, inherited organization groups, and site groups.
598             * </li>
599             * </ul>
600             *
601             * @param      classNames the group entity class names (optionally
602             *             <code>null</code>). For more information see {@link
603             *             #getUserSitesGroups(String[], int)}.
604             * @param      max the maximum number of groups to return
605             * @return     the user's groups &quot;sites&quot;
606             * @throws     PortalException if a portal exception occurred
607             * @deprecated As of 6.2.0, replaced by {@link #getUserSitesGroups(String[],
608             *             int)}
609             */
610            @Deprecated
611            @Override
612            public List<Group> getUserPlaces(String[] classNames, int max)
613                    throws PortalException {
614    
615                    return getUserSitesGroups(classNames, max);
616            }
617    
618            /**
619             * Returns the number of the guest or current user's groups
620             * &quot;sites&quot; associated with the group entity class names, including
621             * the Control Panel group if the user is permitted to view the Control
622             * Panel.
623             *
624             * @return     the number of user's groups &quot;sites&quot;
625             * @throws     PortalException if a portal exception occurred
626             * @deprecated As of 6.2.0, replaced by {@link #getUserSitesGroupsCount()}
627             */
628            @Deprecated
629            @Override
630            public int getUserPlacesCount() throws PortalException {
631                    return getUserSitesGroupsCount();
632            }
633    
634            /**
635             * Returns the guest or current user's layout set group, organization
636             * groups, inherited organization groups, and site groups.
637             *
638             * @return     the user's layout set group, organization groups, and
639             *             inherited organization groups, and site groups
640             * @throws     PortalException if a portal exception occurred
641             * @deprecated As of 6.2.0, replaced by {@link #getUserSitesGroups}
642             */
643            @Deprecated
644            @Override
645            public List<Group> getUserSites() throws PortalException {
646                    return getUserSitesGroups();
647            }
648    
649            @Override
650            public List<Group> getUserSitesGroups() throws PortalException {
651                    return getUserSitesGroups(null, QueryUtil.ALL_POS);
652            }
653    
654            @Override
655            public List<Group> getUserSitesGroups(
656                            long userId, String[] classNames, boolean includeControlPanel,
657                            int max)
658                    throws PortalException {
659    
660                    User user = userPersistence.fetchByPrimaryKey(userId);
661    
662                    if (user.isDefaultUser()) {
663                            return Collections.emptyList();
664                    }
665    
666                    List<Group> userSiteGroups = new ArrayList<Group>();
667    
668                    int start = QueryUtil.ALL_POS;
669                    int end = QueryUtil.ALL_POS;
670    
671                    if (max != QueryUtil.ALL_POS) {
672                            start = 0;
673                            end = max;
674                    }
675    
676                    if ((classNames == null) ||
677                            ArrayUtil.contains(classNames, Group.class.getName())) {
678    
679                            LinkedHashMap<String, Object> groupParams =
680                                    new LinkedHashMap<String, Object>();
681    
682                            groupParams.put("active", true);
683                            groupParams.put("usersGroups", userId);
684    
685                            userSiteGroups.addAll(
686                                    groupLocalService.search(
687                                            user.getCompanyId(), null, groupParams, start, end));
688                    }
689    
690                    if ((classNames == null) ||
691                            ArrayUtil.contains(classNames, Organization.class.getName())) {
692    
693                            List<Organization> userOrgs =
694                                    organizationLocalService.getOrganizations(
695                                            userId, start, end, null);
696    
697                            for (Organization organization : userOrgs) {
698                                    if (!organization.hasPrivateLayouts() &&
699                                            !organization.hasPublicLayouts()) {
700    
701                                            userSiteGroups.remove(organization.getGroup());
702                                    }
703                                    else {
704                                            userSiteGroups.add(0, organization.getGroup());
705                                    }
706    
707                                    if (!PropsValues.ORGANIZATIONS_MEMBERSHIP_STRICT) {
708                                            for (Organization ancestorOrganization :
709                                                            organization.getAncestors()) {
710    
711                                                    if (!ancestorOrganization.hasPrivateLayouts() &&
712                                                            !ancestorOrganization.hasPublicLayouts()) {
713    
714                                                            continue;
715                                                    }
716    
717                                                    userSiteGroups.add(0, ancestorOrganization.getGroup());
718                                            }
719                                    }
720                            }
721                    }
722    
723                    if ((classNames == null) ||
724                            ArrayUtil.contains(classNames, User.class.getName())) {
725    
726                            if (PropsValues.LAYOUT_USER_PRIVATE_LAYOUTS_ENABLED ||
727                                    PropsValues.LAYOUT_USER_PUBLIC_LAYOUTS_ENABLED) {
728    
729                                    Group userGroup = user.getGroup();
730    
731                                    userSiteGroups.add(0, userGroup);
732                            }
733                    }
734    
735                    PermissionChecker permissionChecker = getPermissionChecker();
736    
737                    if (permissionChecker.getUserId() != userId) {
738                            try {
739                                    permissionChecker = PermissionCheckerFactoryUtil.create(user);
740                            }
741                            catch (Exception e) {
742                                    throw new PrincipalException(e);
743                            }
744                    }
745    
746                    if (includeControlPanel &&
747                            PortalPermissionUtil.contains(
748                                    permissionChecker, ActionKeys.VIEW_CONTROL_PANEL)) {
749    
750                            Group controlPanelGroup = groupLocalService.getGroup(
751                                    user.getCompanyId(), GroupConstants.CONTROL_PANEL);
752    
753                            userSiteGroups.add(0, controlPanelGroup);
754                    }
755    
756                    return Collections.unmodifiableList(
757                            ListUtil.subList(ListUtil.unique(userSiteGroups), start, end));
758            }
759    
760            /**
761             * Returns the user's groups &quot;sites&quot; associated with the group
762             * entity class names, including the Control Panel group if the user is
763             * permitted to view the Control Panel.
764             *
765             * <ul>
766             * <li>
767             * Class name &quot;User&quot; includes the user's layout set
768             * group.
769             * </li>
770             * <li>
771             * Class name &quot;Organization&quot; includes the user's
772             * immediate organization groups and inherited organization groups.
773             * </li>
774             * <li>
775             * Class name &quot;Group&quot; includes the user's immediate
776             * organization groups and site groups.
777             * </li>
778             * <li>
779             * A <code>classNames</code>
780             * value of <code>null</code> includes the user's layout set group,
781             * organization groups, inherited organization groups, and site groups.
782             * </li>
783             * </ul>
784             *
785             * @param  userId the primary key of the user
786             * @param  classNames the group entity class names (optionally
787             *         <code>null</code>). For more information see {@link
788             *         #getUserSitesGroups(long, String[], boolean, int)}.
789             * @param  max the maximum number of groups to return
790             * @return the user's groups &quot;sites&quot;
791             * @throws PortalException if a portal exception occurred
792             */
793            @Override
794            public List<Group> getUserSitesGroups(
795                            long userId, String[] classNames, int max)
796                    throws PortalException {
797    
798                    return getUserSitesGroups(userId, classNames, false, max);
799            }
800    
801            /**
802             * Returns the guest or current user's groups &quot;sites&quot; associated
803             * with the group entity class names, including the Control Panel group if
804             * the user is permitted to view the Control Panel.
805             *
806             * <ul>
807             * <li>
808             * Class name &quot;User&quot; includes the user's layout set
809             * group.
810             * </li>
811             * <li>
812             * Class name &quot;Organization&quot; includes the user's
813             * immediate organization groups and inherited organization groups.
814             * </li>
815             * <li>
816             * Class name &quot;Group&quot; includes the user's immediate
817             * organization groups and site groups.
818             * </li>
819             * <li>
820             * A <code>classNames</code>
821             * value of <code>null</code> includes the user's layout set group,
822             * organization groups, inherited organization groups, and site groups.
823             * </li>
824             * </ul>
825             *
826             * @param  classNames the group entity class names (optionally
827             *         <code>null</code>). For more information see {@link
828             *         #getUserSitesGroups(long, String[], boolean, int)}.
829             * @param  max the maximum number of groups to return
830             * @return the user's groups &quot;sites&quot;
831             * @throws PortalException if a portal exception occurred
832             */
833            @Override
834            public List<Group> getUserSitesGroups(String[] classNames, int max)
835                    throws PortalException {
836    
837                    return getUserSitesGroups(getGuestOrUserId(), classNames, false, max);
838            }
839    
840            /**
841             * Returns the number of the guest or current user's groups
842             * &quot;sites&quot; associated with the group entity class names, including
843             * the Control Panel group if the user is permitted to view the Control
844             * Panel.
845             *
846             * @return the number of user's groups &quot;sites&quot;
847             * @throws PortalException if a portal exception occurred
848             */
849            @Override
850            public int getUserSitesGroupsCount() throws PortalException {
851                    List<Group> userSitesGroups = getUserSitesGroups(
852                            getGuestOrUserId(), null, true, QueryUtil.ALL_POS);
853    
854                    return userSitesGroups.size();
855            }
856    
857            /**
858             * Returns <code>true</code> if the user is associated with the group,
859             * including the user's inherited organizations and user groups. System and
860             * staged groups are not included.
861             *
862             * @param  userId the primary key of the user
863             * @param  groupId the primary key of the group
864             * @return <code>true</code> if the user is associated with the group;
865             *         <code>false</code> otherwise
866             * @throws PortalException if the current user did not have permission to
867             *         view the user or group members
868             */
869            @Override
870            public boolean hasUserGroup(long userId, long groupId)
871                    throws PortalException {
872    
873                    try {
874                            UserPermissionUtil.check(
875                                    getPermissionChecker(), userId, ActionKeys.VIEW);
876                    }
877                    catch (PrincipalException pe) {
878                            GroupPermissionUtil.check(
879                                    getPermissionChecker(), groupId, ActionKeys.VIEW_MEMBERS);
880                    }
881    
882                    return groupLocalService.hasUserGroup(userId, groupId);
883            }
884    
885            @Override
886            public List<Group> search(
887                            long companyId, long[] classNameIds, String keywords,
888                            LinkedHashMap<String, Object> params, int start, int end,
889                            OrderByComparator<Group> obc)
890                    throws PortalException {
891    
892                    List<Group> groups = groupLocalService.search(
893                            companyId, classNameIds, keywords, params, start, end, obc);
894    
895                    return filterGroups(groups);
896            }
897    
898            @Override
899            public List<Group> search(
900                            long companyId, long[] classNameIds, String name,
901                            String description, LinkedHashMap<String, Object> params,
902                            boolean andOperator, int start, int end,
903                            OrderByComparator<Group> obc)
904                    throws PortalException {
905    
906                    List<Group> groups = groupLocalService.search(
907                            companyId, classNameIds, name, description, params, andOperator,
908                            start, end, obc);
909    
910                    return filterGroups(groups);
911            }
912    
913            /**
914             * Returns an ordered range of all the site groups and organization groups
915             * that match the name and description, optionally including the user's
916             * inherited organization groups and user groups. System and staged groups
917             * are not included.
918             *
919             * <p>
920             * Useful when paginating results. Returns a maximum of <code>end -
921             * start</code> instances. <code>start</code> and <code>end</code> are not
922             * primary keys, they are indexes in the result set. Thus, <code>0</code>
923             * refers to the first result in the set. Setting both <code>start</code>
924             * and <code>end</code> to {@link
925             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
926             * result set.
927             * </p>
928             *
929             * @param  companyId the primary key of the company
930             * @param  name the group's name (optionally <code>null</code>)
931             * @param  description the group's description (optionally
932             *         <code>null</code>)
933             * @param  params the finder params (optionally <code>null</code>). To
934             *         include the user's inherited organizations and user groups in the
935             *         search, add entries having &quot;usersGroups&quot; and
936             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
937             *         information see {@link
938             *         com.liferay.portal.service.persistence.GroupFinder}.
939             * @param  start the lower bound of the range of groups to return
940             * @param  end the upper bound of the range of groups to return (not
941             *         inclusive)
942             * @return the matching groups ordered by name
943             * @throws PortalException if a portal exception occurred
944             */
945            @Override
946            public List<Group> search(
947                            long companyId, String name, String description, String[] params,
948                            int start, int end)
949                    throws PortalException {
950    
951                    if (params == null) {
952                            params = new String[0];
953                    }
954    
955                    LinkedHashMap<String, Object> paramsObj = MapUtil.toLinkedHashMap(
956                            params);
957    
958                    List<Group> groups = groupLocalService.search(
959                            companyId, name, description, paramsObj, true, start, end);
960    
961                    return filterGroups(groups);
962            }
963    
964            /**
965             * Returns the number of groups and organization groups that match the name
966             * and description, optionally including the user's inherited organizations
967             * and user groups. System and staged groups are not included.
968             *
969             * @param  companyId the primary key of the company
970             * @param  name the group's name (optionally <code>null</code>)
971             * @param  description the group's description (optionally
972             *         <code>null</code>)
973             * @param  params the finder params (optionally <code>null</code>). To
974             *         include the user's inherited organizations and user groups in the
975             *         search, add entries having &quot;usersGroups&quot; and
976             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
977             *         information see {@link
978             *         com.liferay.portal.service.persistence.GroupFinder}.
979             * @return the number of matching groups
980             */
981            @Override
982            public int searchCount(
983                    long companyId, String name, String description, String[] params) {
984    
985                    if (params == null) {
986                            params = new String[0];
987                    }
988    
989                    LinkedHashMap<String, Object> paramsObj = MapUtil.toLinkedHashMap(
990                            params);
991    
992                    return groupLocalService.searchCount(
993                            companyId, name, description, paramsObj, true);
994            }
995    
996            /**
997             * Sets the groups associated with the role, removing and adding
998             * associations as necessary.
999             *
1000             * @param  roleId the primary key of the role
1001             * @param  groupIds the primary keys of the groups
1002             * @throws PortalException if the user did not have permission to update
1003             *         update the role
1004             */
1005            @Override
1006            public void setRoleGroups(long roleId, long[] groupIds)
1007                    throws PortalException {
1008    
1009                    RolePermissionUtil.check(
1010                            getPermissionChecker(), roleId, ActionKeys.ASSIGN_MEMBERS);
1011    
1012                    groupLocalService.setRoleGroups(roleId, groupIds);
1013            }
1014    
1015            /**
1016             * Removes the groups from the role.
1017             *
1018             * @param  roleId the primary key of the role
1019             * @param  groupIds the primary keys of the groups
1020             * @throws PortalException if the user did not have permission to update the
1021             *         role
1022             */
1023            @Override
1024            public void unsetRoleGroups(long roleId, long[] groupIds)
1025                    throws PortalException {
1026    
1027                    RolePermissionUtil.check(
1028                            getPermissionChecker(), roleId, ActionKeys.ASSIGN_MEMBERS);
1029    
1030                    groupLocalService.unsetRoleGroups(roleId, groupIds);
1031            }
1032    
1033            /**
1034             * Updates the group's friendly URL.
1035             *
1036             * @param  groupId the primary key of the group
1037             * @param  friendlyURL the group's new friendlyURL (optionally
1038             *         <code>null</code>)
1039             * @return the group
1040             * @throws PortalException if the user did not have permission to update the
1041             *         group, if a group with the primary key could not be found, or if
1042             *         a valid friendly URL could not be created for the group
1043             */
1044            @Override
1045            public Group updateFriendlyURL(long groupId, String friendlyURL)
1046                    throws PortalException {
1047    
1048                    GroupPermissionUtil.check(
1049                            getPermissionChecker(), groupId, ActionKeys.UPDATE);
1050    
1051                    return groupLocalService.updateFriendlyURL(groupId, friendlyURL);
1052            }
1053    
1054            /**
1055             * Updates the group.
1056             *
1057             * @param  groupId the primary key of the group
1058             * @param  parentGroupId the primary key of the parent group
1059             * @param  name the group's new name
1060             * @param  description the group's new description (optionally
1061             *         <code>null</code>)
1062             * @param  type the group's new type. For more information see {@link
1063             *         GroupConstants}.
1064             * @param  manualMembership whether manual membership is allowed for the
1065             *         group
1066             * @param  membershipRestriction the group's membership restriction. For
1067             *         more information see {@link GroupConstants}.
1068             * @param  friendlyURL the group's new friendlyURL (optionally
1069             *         <code>null</code>)
1070             * @param  active whether the group is active
1071             * @param  serviceContext the service context to be applied (optionally
1072             *         <code>null</code>). Can set the asset category IDs and asset tag
1073             *         names for the group.
1074             * @return the group
1075             * @throws PortalException if the user did not have permission to update the
1076             *         group, if a group with the primary key could not be found, if the
1077             *         friendly URL was invalid or could one not be created
1078             */
1079            @Override
1080            public Group updateGroup(
1081                            long groupId, long parentGroupId, String name, String description,
1082                            int type, boolean manualMembership, int membershipRestriction,
1083                            String friendlyURL, boolean inheritContent, boolean active,
1084                            ServiceContext serviceContext)
1085                    throws PortalException {
1086    
1087                    Group group = groupPersistence.findByPrimaryKey(groupId);
1088    
1089                    GroupPermissionUtil.check(
1090                            getPermissionChecker(), group, ActionKeys.UPDATE);
1091    
1092                    if (group.getParentGroupId() != parentGroupId) {
1093                            if (parentGroupId == GroupConstants.DEFAULT_PARENT_GROUP_ID) {
1094                                    PortalPermissionUtil.check(
1095                                            getPermissionChecker(), ActionKeys.ADD_COMMUNITY);
1096                            }
1097                            else {
1098                                    GroupPermissionUtil.check(
1099                                            getPermissionChecker(), parentGroupId,
1100                                            ActionKeys.ADD_COMMUNITY);
1101                            }
1102                    }
1103    
1104                    if (group.isSite()) {
1105                            Group oldGroup = group;
1106    
1107                            List<AssetCategory> oldAssetCategories =
1108                                    assetCategoryLocalService.getCategories(
1109                                            Group.class.getName(), groupId);
1110    
1111                            List<AssetTag> oldAssetTags = assetTagLocalService.getTags(
1112                                    Group.class.getName(), groupId);
1113    
1114                            ExpandoBridge oldExpandoBridge = oldGroup.getExpandoBridge();
1115    
1116                            Map<String, Serializable> oldExpandoAttributes =
1117                                    oldExpandoBridge.getAttributes();
1118    
1119                            group = groupLocalService.updateGroup(
1120                                    groupId, parentGroupId, name, description, type,
1121                                    manualMembership, membershipRestriction, friendlyURL,
1122                                    inheritContent, active, serviceContext);
1123    
1124                            SiteMembershipPolicyUtil.verifyPolicy(
1125                                    group, oldGroup, oldAssetCategories, oldAssetTags,
1126                                    oldExpandoAttributes, null);
1127    
1128                            return group;
1129                    }
1130                    else {
1131                            return groupLocalService.updateGroup(
1132                                    groupId, parentGroupId, name, description, type,
1133                                    manualMembership, membershipRestriction, friendlyURL,
1134                                    inheritContent, active, serviceContext);
1135                    }
1136            }
1137    
1138            /**
1139             * Updates the group's type settings.
1140             *
1141             * @param  groupId the primary key of the group
1142             * @param  typeSettings the group's new type settings (optionally
1143             *         <code>null</code>)
1144             * @return the group
1145             * @throws PortalException if the user did not have permission to update the
1146             *         group or if a group with the primary key could not be found
1147             */
1148            @Override
1149            public Group updateGroup(long groupId, String typeSettings)
1150                    throws PortalException {
1151    
1152                    Group group = groupPersistence.findByPrimaryKey(groupId);
1153    
1154                    GroupPermissionUtil.check(
1155                            getPermissionChecker(), group, ActionKeys.UPDATE);
1156    
1157                    if (group.isSite()) {
1158                            Group oldGroup = group;
1159    
1160                            UnicodeProperties oldTypeSettingsProperties =
1161                                    oldGroup.getTypeSettingsProperties();
1162    
1163                            group = groupLocalService.updateGroup(groupId, typeSettings);
1164    
1165                            SiteMembershipPolicyUtil.verifyPolicy(
1166                                    group, oldGroup, null, null, null, oldTypeSettingsProperties);
1167    
1168                            return group;
1169                    }
1170                    else {
1171                            return groupLocalService.updateGroup(groupId, typeSettings);
1172                    }
1173            }
1174    
1175            @Override
1176            public void updateStagedPortlets(
1177                            long groupId, Map<String, String> stagedPortletIds)
1178                    throws PortalException {
1179    
1180                    Group group = groupPersistence.findByPrimaryKey(groupId);
1181    
1182                    GroupPermissionUtil.check(
1183                            getPermissionChecker(), group, ActionKeys.UPDATE);
1184    
1185                    UnicodeProperties typeSettingsProperties =
1186                            group.getTypeSettingsProperties();
1187    
1188                    for (String stagedPortletId : stagedPortletIds.keySet()) {
1189                            typeSettingsProperties.setProperty(
1190                                    StagingUtil.getStagedPortletId(stagedPortletId),
1191                                    stagedPortletIds.get(stagedPortletId));
1192                    }
1193    
1194                    groupLocalService.updateGroup(group);
1195            }
1196    
1197            protected List<Group> filterGroups(List<Group> groups)
1198                    throws PortalException {
1199    
1200                    List<Group> filteredGroups = new ArrayList<Group>();
1201    
1202                    for (Group group : groups) {
1203                            if (GroupPermissionUtil.contains(
1204                                            getPermissionChecker(), group, ActionKeys.VIEW)) {
1205    
1206                                    filteredGroups.add(group);
1207                            }
1208                    }
1209    
1210                    return filteredGroups;
1211            }
1212    
1213    }