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