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.LocaleException;
018    import com.liferay.portal.exception.DuplicateGroupException;
019    import com.liferay.portal.exception.GroupFriendlyURLException;
020    import com.liferay.portal.exception.GroupInheritContentException;
021    import com.liferay.portal.exception.GroupKeyException;
022    import com.liferay.portal.exception.GroupParentException;
023    import com.liferay.portal.exception.NoSuchGroupException;
024    import com.liferay.portal.exception.NoSuchLayoutSetException;
025    import com.liferay.portal.exception.PendingBackgroundTaskException;
026    import com.liferay.portal.exception.RequiredGroupException;
027    import com.liferay.portal.kernel.backgroundtask.BackgroundTask;
028    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskConstants;
029    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskManagerUtil;
030    import com.liferay.portal.kernel.cache.thread.local.ThreadLocalCachable;
031    import com.liferay.portal.kernel.dao.orm.QueryUtil;
032    import com.liferay.portal.kernel.exception.PortalException;
033    import com.liferay.portal.kernel.exception.SystemException;
034    import com.liferay.portal.kernel.language.LanguageUtil;
035    import com.liferay.portal.kernel.log.Log;
036    import com.liferay.portal.kernel.log.LogFactoryUtil;
037    import com.liferay.portal.kernel.messaging.DestinationNames;
038    import com.liferay.portal.kernel.scheduler.SchedulerEngineHelperUtil;
039    import com.liferay.portal.kernel.scheduler.StorageType;
040    import com.liferay.portal.kernel.spring.aop.Skip;
041    import com.liferay.portal.kernel.transaction.Propagation;
042    import com.liferay.portal.kernel.transaction.Transactional;
043    import com.liferay.portal.kernel.util.ArrayUtil;
044    import com.liferay.portal.kernel.util.CharPool;
045    import com.liferay.portal.kernel.util.FileUtil;
046    import com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil;
047    import com.liferay.portal.kernel.util.GetterUtil;
048    import com.liferay.portal.kernel.util.GroupThreadLocal;
049    import com.liferay.portal.kernel.util.ListUtil;
050    import com.liferay.portal.kernel.util.LocaleUtil;
051    import com.liferay.portal.kernel.util.MapUtil;
052    import com.liferay.portal.kernel.util.OrderByComparator;
053    import com.liferay.portal.kernel.util.ParamUtil;
054    import com.liferay.portal.kernel.util.PropsKeys;
055    import com.liferay.portal.kernel.util.StringBundler;
056    import com.liferay.portal.kernel.util.StringPool;
057    import com.liferay.portal.kernel.util.StringUtil;
058    import com.liferay.portal.kernel.util.TreeModelTasksAdapter;
059    import com.liferay.portal.kernel.util.TreePathUtil;
060    import com.liferay.portal.kernel.util.UnicodeProperties;
061    import com.liferay.portal.kernel.util.Validator;
062    import com.liferay.portal.kernel.workflow.WorkflowHandler;
063    import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
064    import com.liferay.portal.model.Account;
065    import com.liferay.portal.model.Company;
066    import com.liferay.portal.model.Group;
067    import com.liferay.portal.model.GroupConstants;
068    import com.liferay.portal.model.Layout;
069    import com.liferay.portal.model.LayoutConstants;
070    import com.liferay.portal.model.LayoutPrototype;
071    import com.liferay.portal.model.LayoutSet;
072    import com.liferay.portal.model.LayoutSetPrototype;
073    import com.liferay.portal.model.LayoutTemplate;
074    import com.liferay.portal.model.LayoutTypePortlet;
075    import com.liferay.portal.model.Organization;
076    import com.liferay.portal.model.Portlet;
077    import com.liferay.portal.model.ResourceAction;
078    import com.liferay.portal.model.ResourceConstants;
079    import com.liferay.portal.model.ResourcePermission;
080    import com.liferay.portal.model.ResourceTypePermission;
081    import com.liferay.portal.model.Role;
082    import com.liferay.portal.model.RoleConstants;
083    import com.liferay.portal.model.User;
084    import com.liferay.portal.model.UserGroup;
085    import com.liferay.portal.model.UserGroupRole;
086    import com.liferay.portal.model.UserPersonalSite;
087    import com.liferay.portal.model.WorkflowDefinitionLink;
088    import com.liferay.portal.model.impl.LayoutImpl;
089    import com.liferay.portal.security.auth.CompanyThreadLocal;
090    import com.liferay.portal.security.permission.ActionKeys;
091    import com.liferay.portal.security.permission.PermissionCacheUtil;
092    import com.liferay.portal.security.permission.ResourceActionsUtil;
093    import com.liferay.portal.security.permission.RolePermissions;
094    import com.liferay.portal.service.ServiceContext;
095    import com.liferay.portal.service.base.GroupLocalServiceBaseImpl;
096    import com.liferay.portal.theme.ThemeLoader;
097    import com.liferay.portal.theme.ThemeLoaderFactory;
098    import com.liferay.portal.util.PortalUtil;
099    import com.liferay.portal.util.PortletCategoryKeys;
100    import com.liferay.portal.util.PortletKeys;
101    import com.liferay.portal.util.PropsUtil;
102    import com.liferay.portal.util.PropsValues;
103    import com.liferay.portal.util.comparator.GroupIdComparator;
104    import com.liferay.portal.util.comparator.GroupNameComparator;
105    import com.liferay.portlet.exportimport.configuration.ExportImportConfigurationConstants;
106    import com.liferay.portlet.exportimport.configuration.ExportImportConfigurationSettingsMapFactory;
107    import com.liferay.portlet.exportimport.lar.PortletDataContext;
108    import com.liferay.portlet.exportimport.lar.PortletDataContextFactoryUtil;
109    import com.liferay.portlet.exportimport.lar.PortletDataHandler;
110    import com.liferay.portlet.exportimport.lar.PortletDataHandlerKeys;
111    import com.liferay.portlet.exportimport.model.ExportImportConfiguration;
112    import com.liferay.portlet.exportimport.staging.StagingConstants;
113    import com.liferay.portlet.exportimport.staging.StagingUtil;
114    import com.liferay.util.dao.orm.CustomSQLUtil;
115    
116    import java.io.File;
117    import java.io.Serializable;
118    
119    import java.util.ArrayList;
120    import java.util.Arrays;
121    import java.util.Collection;
122    import java.util.Collections;
123    import java.util.HashMap;
124    import java.util.HashSet;
125    import java.util.Iterator;
126    import java.util.LinkedHashMap;
127    import java.util.List;
128    import java.util.Locale;
129    import java.util.Map;
130    import java.util.Set;
131    
132    /**
133     * Provides the local service for accessing, adding, deleting, and updating
134     * groups. Groups are mostly used in Liferay as a resource container for
135     * permissioning and content scoping purposes.
136     *
137     * <p>
138     * Groups are also the entity to which LayoutSets are generally associated.
139     * Since LayoutSets are the parent entities of Layouts (i.e. pages), no entity
140     * can have associated pages without also having an associated Group. This
141     * relationship can be depicted as ... Layout -> LayoutSet -> Group[type] [->
142     * Entity]. Note, the Entity part is optional.
143     * </p>
144     *
145     * <p>
146     * Group has a "type" definition that is typically identified by two fields of
147     * the entity - <code>String className</code>, and <code>int type </code>.
148     * </p>
149     *
150     * <p>
151     * The <code>className</code> field helps create the group's association with
152     * other entities (e.g. Organization, User, Company, UserGroup, ... etc.). The
153     * value of <code>className</code> is the full name of the entity's class and
154     * the primary key of the associated entity instance. A site has
155     * <code>className="Group"</code> and has no associated entity.
156     * </p>
157     *
158     * <p>
159     * The <code>type</code> field helps distinguish between a group used strictly
160     * for scoping and a group that also has pages (in which case the type is
161     * <code>SITE</code>). For a list of types, see {@link GroupConstants}.
162     * </p>
163     *
164     * <p>
165     * Here is a listing of how Group is related to some portal entities ...
166     * </p>
167     *
168     * <ul>
169     * <li>
170     * Site is a Group with <code>className="Group"</code>
171     * </li>
172     * <li>
173     * Company has 1 Group (this is the global scope, but never has pages)
174     * </li>
175     * <li>
176     * User has 1 Group (pages are optional based on the behavior configuration for
177     * personal pages)
178     * </li>
179     * <li>
180     * Layout Template (<code>LayoutPrototype</code>) has 1 Group which uses only 1
181     * of it's 2 LayoutSets to store a single page which can later be used to
182     * derive a single page in any Site
183     * </li>
184     * <li>
185     * Site Template (<code>LayoutSetPrototype</code>) has 1 Group which uses only
186     * 1 of it's 2 LayoutSets to store many pages which can later be used to derive
187     * entire Sites or pulled into an existing Site
188     * </li>
189     * <li>
190     * Organization has 1 Group, but can also be associated to a Site at any point
191     * in it's life cycle in order to support having pages
192     * </li>
193     * <li>
194     * UserGroup has 1 Group that can have pages in both of the group's LayoutSets
195     * which are later inherited by users assigned to the UserGroup
196     * </li>
197     * </ul>
198     *
199     * @author Brian Wing Shun Chan
200     * @author Alexander Chow
201     * @author Bruno Farache
202     * @author Wesley Gong
203     * @see    com.liferay.portal.model.impl.GroupImpl
204     */
205    public class GroupLocalServiceImpl extends GroupLocalServiceBaseImpl {
206    
207            public static final String ORGANIZATION_NAME_SUFFIX = " LFR_ORGANIZATION";
208    
209            public static final String ORGANIZATION_STAGING_SUFFIX = " (Staging)";
210    
211            /**
212             * Constructs a group local service.
213             */
214            public GroupLocalServiceImpl() {
215                    initImportLARFile();
216            }
217    
218            @Override
219            public Group addGroup(
220                            long userId, long parentGroupId, String className, long classPK,
221                            long liveGroupId, Map<Locale, String> nameMap,
222                            Map<Locale, String> descriptionMap, int type,
223                            boolean manualMembership, int membershipRestriction,
224                            String friendlyURL, boolean site, boolean inheritContent,
225                            boolean active, ServiceContext serviceContext)
226                    throws PortalException {
227    
228                    // Group
229    
230                    User user = userPersistence.findByPrimaryKey(userId);
231                    className = GetterUtil.getString(className);
232                    long classNameId = classNameLocalService.getClassNameId(className);
233    
234                    String groupKey = StringPool.BLANK;
235                    String friendlyName = StringPool.BLANK;
236    
237                    if (nameMap != null) {
238                            groupKey = nameMap.get(LocaleUtil.getDefault());
239                            friendlyName = nameMap.get(LocaleUtil.getDefault());
240                    }
241    
242                    long groupId = 0;
243    
244                    while (true) {
245                            groupId = counterLocalService.increment();
246    
247                            User screenNameUser = userPersistence.fetchByC_SN(
248                                    user.getCompanyId(), String.valueOf(groupId));
249    
250                            if (screenNameUser == null) {
251                                    break;
252                            }
253                    }
254    
255                    boolean staging = isStaging(serviceContext);
256    
257                    long groupClassNameId = classNameLocalService.getClassNameId(
258                            Group.class);
259    
260                    if ((classNameId <= 0) || className.equals(Group.class.getName()) ||
261                            (className.equals(Company.class.getName()) && staging)) {
262    
263                            className = Group.class.getName();
264                            classNameId = groupClassNameId;
265                            classPK = groupId;
266                    }
267                    else if (className.equals(Organization.class.getName())) {
268                            groupKey = getOrgGroupName(groupKey);
269                    }
270                    else if (!GroupConstants.USER_PERSONAL_SITE.equals(groupKey)) {
271                            groupKey = String.valueOf(classPK);
272                    }
273    
274                    if (className.equals(Organization.class.getName()) && staging) {
275                            classPK = liveGroupId;
276                    }
277    
278                    if (className.equals(Layout.class.getName())) {
279                            Layout layout = layoutLocalService.getLayout(classPK);
280    
281                            parentGroupId = layout.getGroupId();
282                    }
283    
284                    friendlyURL = getFriendlyURL(
285                            user.getCompanyId(), groupId, classNameId, classPK, friendlyName,
286                            friendlyURL);
287    
288                    if (staging) {
289                            groupKey = groupKey.concat("-staging");
290    
291                            for (Locale locale : nameMap.keySet()) {
292                                    String name = nameMap.get(locale);
293    
294                                    if (Validator.isNull(name)) {
295                                            continue;
296                                    }
297    
298                                    nameMap.put(locale, name.concat(ORGANIZATION_STAGING_SUFFIX));
299                            }
300    
301                            friendlyURL = getFriendlyURL(friendlyURL.concat("-staging"));
302                    }
303    
304                    if (parentGroupId == GroupConstants.DEFAULT_PARENT_GROUP_ID) {
305                            membershipRestriction =
306                                    GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION;
307                    }
308    
309                    if (className.equals(Group.class.getName())) {
310                            if (!site && (liveGroupId == 0) &&
311                                    !(groupKey.equals(GroupConstants.CONTROL_PANEL) ||
312                                      groupKey.equals(GroupConstants.FORMS))) {
313    
314                                    throw new IllegalArgumentException();
315                            }
316                    }
317                    else if (!className.equals(Company.class.getName()) &&
318                                     !className.equals(Organization.class.getName()) &&
319                                     className.startsWith("com.liferay.portal.model.")) {
320    
321                            if (site) {
322                                    throw new IllegalArgumentException();
323                            }
324                    }
325    
326                    if ((classNameId <= 0) || className.equals(Group.class.getName())) {
327                            validateGroupKey(groupId, user.getCompanyId(), groupKey, site);
328                    }
329    
330                    validateInheritContent(parentGroupId, inheritContent);
331    
332                    validateFriendlyURL(
333                            user.getCompanyId(), groupId, classNameId, classPK, friendlyURL);
334    
335                    validateParentGroup(groupId, parentGroupId);
336    
337                    Group group = groupPersistence.create(groupId);
338    
339                    if (serviceContext != null) {
340                            group.setUuid(serviceContext.getUuid());
341                    }
342    
343                    group.setCompanyId(user.getCompanyId());
344                    group.setCreatorUserId(userId);
345                    group.setClassNameId(classNameId);
346                    group.setClassPK(classPK);
347                    group.setParentGroupId(parentGroupId);
348                    group.setLiveGroupId(liveGroupId);
349                    group.setTreePath(group.buildTreePath());
350                    group.setGroupKey(groupKey);
351                    group.setNameMap(nameMap);
352                    group.setDescriptionMap(descriptionMap);
353                    group.setType(type);
354                    group.setManualMembership(manualMembership);
355                    group.setMembershipRestriction(membershipRestriction);
356                    group.setFriendlyURL(friendlyURL);
357                    group.setInheritContent(inheritContent);
358                    group.setSite(site);
359                    group.setActive(active);
360    
361                    if ((serviceContext != null) && (classNameId == groupClassNameId) &&
362                            !user.isDefaultUser()) {
363    
364                            group.setExpandoBridgeAttributes(serviceContext);
365                    }
366    
367                    groupPersistence.update(group);
368    
369                    // Layout sets
370    
371                    layoutSetLocalService.addLayoutSet(groupId, true);
372    
373                    layoutSetLocalService.addLayoutSet(groupId, false);
374    
375                    // Resources
376    
377                    resourceLocalService.addResources(
378                            group.getCompanyId(), 0, 0, Group.class.getName(),
379                            group.getGroupId(), false, false, false);
380    
381                    if ((classNameId == groupClassNameId) && !user.isDefaultUser()) {
382    
383                            // Site roles
384    
385                            Role role = roleLocalService.getRole(
386                                    group.getCompanyId(), RoleConstants.SITE_OWNER);
387    
388                            userGroupRoleLocalService.addUserGroupRoles(
389                                    userId, groupId, new long[] {role.getRoleId()});
390    
391                            // User
392    
393                            userLocalService.addGroupUsers(
394                                    group.getGroupId(), new long[] {userId});
395    
396                            // Asset
397    
398                            if (serviceContext != null) {
399                                    updateAsset(
400                                            userId, group, serviceContext.getAssetCategoryIds(),
401                                            serviceContext.getAssetTagNames());
402                            }
403                    }
404    
405                    addPortletDefaultData(group);
406    
407                    return group;
408            }
409    
410            @Override
411            public Group addGroup(
412                            long userId, long parentGroupId, String className, long classPK,
413                            long liveGroupId, Map<Locale, String> nameMap,
414                            Map<Locale, String> descriptionMap, int type,
415                            boolean manualMembership, int membershipRestriction,
416                            String friendlyURL, boolean site, boolean active,
417                            ServiceContext serviceContext)
418                    throws PortalException {
419    
420                    return addGroup(
421                            userId, parentGroupId, className, classPK, liveGroupId, nameMap,
422                            descriptionMap, type, manualMembership, membershipRestriction,
423                            friendlyURL, site, false, active, serviceContext);
424            }
425    
426            /**
427             * Adds a group.
428             *
429             * @param      userId the primary key of the group's creator/owner
430             * @param      parentGroupId the primary key of the parent group
431             * @param      className the entity's class name
432             * @param      classPK the primary key of the entity's instance
433             * @param      liveGroupId the primary key of the live group
434             * @param      name the entity's name
435             * @param      description the group's description (optionally
436             *             <code>null</code>)
437             * @param      type the group's type. For more information see {@link
438             *             GroupConstants}.
439             * @param      manualMembership whether manual membership is allowed for the
440             *             group
441             * @param      membershipRestriction the group's membership restriction. For
442             *             more information see {@link GroupConstants}.
443             * @param      friendlyURL the group's friendlyURL (optionally
444             *             <code>null</code>)
445             * @param      site whether the group is to be associated with a main site
446             * @param      active whether the group is active
447             * @param      serviceContext the service context to be applied (optionally
448             *             <code>null</code>). Can set asset category IDs and asset tag
449             *             names for the group, and whether the group is for staging.
450             * @return     the group
451             * @throws     PortalException if a portal exception occured
452             * @deprecated As of 7.0.0, replaced by {@link #addGroup(long, long, String,
453             *             long, long, Map, Map, int, boolean, int, String, boolean,
454             *             boolean, ServiceContext)}
455             */
456            @Deprecated
457            @Override
458            public Group addGroup(
459                            long userId, long parentGroupId, String className, long classPK,
460                            long liveGroupId, String name, String description, int type,
461                            boolean manualMembership, int membershipRestriction,
462                            String friendlyURL, boolean site, boolean active,
463                            ServiceContext serviceContext)
464                    throws PortalException {
465    
466                    return addGroup(
467                            userId, parentGroupId, className, classPK, liveGroupId,
468                            getLocalizationMap(name), getLocalizationMap(description), type,
469                            manualMembership, membershipRestriction, friendlyURL, site, false,
470                            active, serviceContext);
471            }
472    
473            /**
474             * Adds the groups to the role.
475             *
476             * @param roleId the primary key of the role
477             * @param groupIds the primary keys of the groups
478             */
479            @Override
480            public void addRoleGroups(long roleId, long[] groupIds) {
481                    rolePersistence.addGroups(roleId, groupIds);
482    
483                    PermissionCacheUtil.clearCache();
484            }
485    
486            /**
487             * Adds the user to the groups.
488             *
489             * @param userId the primary key of the user
490             * @param groupIds the primary keys of the groups
491             */
492            @Override
493            public void addUserGroups(long userId, long[] groupIds) {
494                    userPersistence.addGroups(userId, groupIds);
495    
496                    PermissionCacheUtil.clearCache(userId);
497            }
498    
499            /**
500             * Adds a company group if it does not exist. This method is typically used
501             * when a virtual host is added.
502             *
503             * @param  companyId the primary key of the company
504             * @throws PortalException if a portal exception occurred
505             */
506            @Override
507            @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
508            public void checkCompanyGroup(long companyId) throws PortalException {
509                    long classNameId = classNameLocalService.getClassNameId(Company.class);
510    
511                    int count = groupPersistence.countByC_C_C(
512                            companyId, classNameId, companyId);
513    
514                    if (count == 0) {
515                            long defaultUserId = userLocalService.getDefaultUserId(companyId);
516    
517                            groupLocalService.addGroup(
518                                    defaultUserId, GroupConstants.DEFAULT_PARENT_GROUP_ID,
519                                    Company.class.getName(), companyId,
520                                    GroupConstants.DEFAULT_LIVE_GROUP_ID,
521                                    getLocalizationMap(GroupConstants.GLOBAL), null, 0, true,
522                                    GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION,
523                                    GroupConstants.GLOBAL_FRIENDLY_URL, true, true, null);
524                    }
525            }
526    
527            /**
528             * Creates systems groups and other related data needed by the system on the
529             * very first startup. Also takes care of creating the Control Panel groups
530             * and layouts.
531             *
532             * @param  companyId the primary key of the company
533             * @throws PortalException if a portal exception occurred
534             */
535            @Override
536            @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
537            public void checkSystemGroups(long companyId) throws PortalException {
538                    String companyIdHexString = StringUtil.toHexString(companyId);
539    
540                    for (Group group : groupFinder.findBySystem(companyId)) {
541                            _systemGroupsMap.put(
542                                    companyIdHexString.concat(group.getGroupKey()), group);
543                    }
544    
545                    long defaultUserId = userLocalService.getDefaultUserId(companyId);
546    
547                    String[] systemGroups = PortalUtil.getSystemGroups();
548    
549                    for (String groupKey : systemGroups) {
550                            String groupCacheKey = companyIdHexString.concat(groupKey);
551    
552                            Group group = _systemGroupsMap.get(groupCacheKey);
553    
554                            if (group == null) {
555                                    group = groupPersistence.fetchByC_GK(companyId, groupKey);
556                            }
557    
558                            if (group == null) {
559                                    String className = null;
560                                    long classPK = 0;
561                                    int type = GroupConstants.TYPE_SITE_OPEN;
562                                    String friendlyURL = null;
563                                    boolean site = true;
564    
565                                    if (groupKey.equals(GroupConstants.CONTROL_PANEL)) {
566                                            type = GroupConstants.TYPE_SITE_PRIVATE;
567                                            friendlyURL = GroupConstants.CONTROL_PANEL_FRIENDLY_URL;
568                                            site = false;
569                                    }
570                                    else if (groupKey.equals(GroupConstants.GUEST)) {
571                                            friendlyURL = "/guest";
572                                    }
573                                    else if (groupKey.equals(GroupConstants.USER_PERSONAL_SITE)) {
574                                            className = UserPersonalSite.class.getName();
575                                            classPK = defaultUserId;
576                                            type = GroupConstants.TYPE_SITE_PRIVATE;
577                                            friendlyURL =
578                                                    GroupConstants.USER_PERSONAL_SITE_FRIENDLY_URL;
579                                            site = false;
580                                    }
581    
582                                    group = groupLocalService.addGroup(
583                                            defaultUserId, GroupConstants.DEFAULT_PARENT_GROUP_ID,
584                                            className, classPK, GroupConstants.DEFAULT_LIVE_GROUP_ID,
585                                            getLocalizationMap(groupKey), null, type, true,
586                                            GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION, friendlyURL,
587                                            site, true, null);
588    
589                                    if (groupKey.equals(GroupConstants.USER_PERSONAL_SITE)) {
590                                            initUserPersonalSitePermissions(group);
591                                    }
592                            }
593    
594                            if (group.isControlPanel()) {
595                                    LayoutSet layoutSet = layoutSetLocalService.getLayoutSet(
596                                            group.getGroupId(), true);
597    
598                                    if (layoutSet.getPageCount() == 0) {
599                                            addControlPanelLayouts(group);
600                                    }
601                            }
602    
603                            if (group.isGuest()) {
604                                    LayoutSet layoutSet = layoutSetLocalService.getLayoutSet(
605                                            group.getGroupId(), false);
606    
607                                    if (layoutSet.getPageCount() == 0) {
608                                            addDefaultGuestPublicLayouts(group);
609                                    }
610                            }
611    
612                            _systemGroupsMap.put(groupCacheKey, group);
613                    }
614            }
615    
616            /**
617             * Deletes the group and its associated data.
618             *
619             * <p>
620             * The group is unstaged and its assets and resources including layouts,
621             * membership requests, subscriptions, teams, blogs, bookmarks, events,
622             * image gallery, journals, message boards, polls, shopping related
623             * entities, and wikis are also deleted.
624             * </p>
625             *
626             * @param  group the group
627             * @return the deleted group
628             * @throws PortalException if a portal exception occurred
629             */
630            @Override
631            public Group deleteGroup(Group group) throws PortalException {
632                    boolean deleteInProcess = GroupThreadLocal.isDeleteInProcess();
633    
634                    try {
635                            GroupThreadLocal.setDeleteInProcess(true);
636    
637                            if (((group.isCompany() && !group.isCompanyStagingGroup()) ||
638                                     PortalUtil.isSystemGroup(group.getGroupKey())) &&
639                                    !CompanyThreadLocal.isDeleteInProcess()) {
640    
641                                    throw new RequiredGroupException.MustNotDeleteSystemGroup(
642                                            group.getGroupId());
643                            }
644    
645                            if (groupPersistence.countByC_P_S(
646                                            group.getCompanyId(), group.getGroupId(), true) > 0) {
647    
648                                    throw new RequiredGroupException.MustNotDeleteGroupThatHasChild(
649                                            group.getGroupId());
650                            }
651    
652                            List<BackgroundTask> backgroundTasks =
653                                    BackgroundTaskManagerUtil.getBackgroundTasks(
654                                            group.getGroupId(),
655                                            BackgroundTaskConstants.STATUS_IN_PROGRESS);
656    
657                            if (!backgroundTasks.isEmpty()) {
658                                    throw new PendingBackgroundTaskException(
659                                            "Unable to delete group with pending background tasks");
660                            }
661    
662                            // Background tasks
663    
664                            BackgroundTaskManagerUtil.deleteGroupBackgroundTasks(
665                                    group.getGroupId());
666    
667                            // Layout set branches
668    
669                            layoutSetBranchLocalService.deleteLayoutSetBranches(
670                                    group.getGroupId(), true, true);
671    
672                            layoutSetBranchLocalService.deleteLayoutSetBranches(
673                                    group.getGroupId(), false, true);
674    
675                            // Layout sets
676    
677                            ServiceContext serviceContext = new ServiceContext();
678    
679                            try {
680                                    layoutSetLocalService.deleteLayoutSet(
681                                            group.getGroupId(), true, serviceContext);
682                            }
683                            catch (NoSuchLayoutSetException nslse) {
684                            }
685    
686                            try {
687                                    layoutSetLocalService.deleteLayoutSet(
688                                            group.getGroupId(), false, serviceContext);
689                            }
690                            catch (NoSuchLayoutSetException nslse) {
691                            }
692    
693                            // Membership requests
694    
695                            membershipRequestLocalService.deleteMembershipRequests(
696                                    group.getGroupId());
697    
698                            // Portlet preferences
699    
700                            portletPreferencesLocalService.deletePortletPreferences(
701                                    group.getGroupId(), PortletKeys.PREFS_OWNER_TYPE_GROUP,
702                                    PortletKeys.PREFS_PLID_SHARED);
703    
704                            // Repositories
705    
706                            dlAppLocalService.deleteAllRepositories(group.getGroupId());
707    
708                            // Teams
709    
710                            teamLocalService.deleteTeams(group.getGroupId());
711    
712                            // Staging
713    
714                            exportImportConfigurationLocalService.
715                                    deleteExportImportConfigurations(group.getGroupId());
716    
717                            unscheduleStaging(group);
718    
719                            if (group.hasStagingGroup()) {
720                                    try {
721                                            stagingLocalService.disableStaging(group, serviceContext);
722                                    }
723                                    catch (Exception e) {
724                                            _log.error(
725                                                    "Unable to disable staging for group " +
726                                                            group.getGroupId());
727                                    }
728                            }
729    
730                            // Themes
731    
732                            ThemeLoader themeLoader =
733                                    ThemeLoaderFactory.getDefaultThemeLoader();
734    
735                            if (themeLoader != null) {
736                                    String themePath =
737                                            themeLoader.getFileStorage() + StringPool.SLASH +
738                                                    group.getGroupId();
739    
740                                    FileUtil.deltree(themePath + "-private");
741                                    FileUtil.deltree(themePath + "-public");
742                            }
743    
744                            // Portlet data
745    
746                            deletePortletData(group);
747    
748                            // Asset
749    
750                            if (group.isRegularSite()) {
751                                    assetEntryLocalService.deleteEntry(
752                                            Group.class.getName(), group.getGroupId());
753                            }
754    
755                            assetEntryLocalService.deleteGroupEntries(group.getGroupId());
756    
757                            assetTagLocalService.deleteGroupTags(group.getGroupId());
758    
759                            assetVocabularyLocalService.deleteVocabularies(group.getGroupId());
760    
761                            // Expando
762    
763                            expandoRowLocalService.deleteRows(group.getGroupId());
764    
765                            // Social
766    
767                            socialActivityLocalService.deleteActivities(group.getGroupId());
768                            socialActivitySettingLocalService.deleteActivitySettings(
769                                    group.getGroupId());
770                            socialRequestLocalService.deleteRequests(
771                                    classNameLocalService.getClassNameId(Group.class),
772                                    group.getGroupId());
773    
774                            // Resources
775    
776                            List<ResourcePermission> resourcePermissions =
777                                    resourcePermissionPersistence.findByC_LikeP(
778                                            group.getCompanyId(), String.valueOf(group.getGroupId()));
779    
780                            for (ResourcePermission resourcePermission : resourcePermissions) {
781                                    resourcePermissionLocalService.deleteResourcePermission(
782                                            resourcePermission);
783                            }
784    
785                            if (!group.isStagingGroup() &&
786                                    (group.isOrganization() || group.isRegularSite())) {
787    
788                                    resourceLocalService.deleteResource(
789                                            group.getCompanyId(), Group.class.getName(),
790                                            ResourceConstants.SCOPE_INDIVIDUAL, group.getGroupId());
791                            }
792    
793                            // Trash
794    
795                            trashEntryLocalService.deleteEntries(group.getGroupId());
796    
797                            // Workflow
798    
799                            List<WorkflowHandler<?>> scopeableWorkflowHandlers =
800                                    WorkflowHandlerRegistryUtil.getScopeableWorkflowHandlers();
801    
802                            for (WorkflowHandler<?> scopeableWorkflowHandler :
803                                            scopeableWorkflowHandlers) {
804    
805                                    if (!scopeableWorkflowHandler.isVisible()) {
806                                            continue;
807                                    }
808    
809                                    WorkflowDefinitionLink workflowDefinitionLink =
810                                            workflowDefinitionLinkLocalService.
811                                                    fetchWorkflowDefinitionLink(
812                                                            group.getCompanyId(), group.getGroupId(),
813                                                            scopeableWorkflowHandler.getClassName(), 0, 0,
814                                                            true);
815    
816                                    if (workflowDefinitionLink == null) {
817                                            continue;
818                                    }
819    
820                                    workflowDefinitionLinkLocalService.deleteWorkflowDefinitionLink(
821                                            workflowDefinitionLink);
822                            }
823    
824                            // Group
825    
826                            if (!group.isStagingGroup() && group.isOrganization() &&
827                                    group.isSite()) {
828    
829                                    group.setSite(false);
830    
831                                    groupPersistence.update(group);
832    
833                                    // Group roles
834    
835                                    userGroupRoleLocalService.deleteUserGroupRoles(
836                                            group.getGroupId(), RoleConstants.TYPE_SITE);
837    
838                                    // User group roles
839    
840                                    userGroupGroupRoleLocalService.deleteUserGroupGroupRoles(
841                                            group.getGroupId(), RoleConstants.TYPE_SITE);
842                            }
843                            else {
844                                    groupPersistence.remove(group);
845    
846                                    // Group roles
847    
848                                    userGroupRoleLocalService.deleteUserGroupRolesByGroupId(
849                                            group.getGroupId());
850    
851                                    // User group roles
852    
853                                    userGroupGroupRoleLocalService.
854                                            deleteUserGroupGroupRolesByGroupId(group.getGroupId());
855                            }
856    
857                            // Permission cache
858    
859                            PermissionCacheUtil.clearCache();
860    
861                            return group;
862                    }
863                    finally {
864                            GroupThreadLocal.setDeleteInProcess(deleteInProcess);
865                    }
866            }
867    
868            /**
869             * Deletes the group and its associated data.
870             *
871             * <p>
872             * The group is unstaged and its assets and resources including layouts,
873             * membership requests, subscriptions, teams, blogs, bookmarks, events,
874             * image gallery, journals, message boards, polls, shopping related
875             * entities, and wikis are also deleted.
876             * </p>
877             *
878             * @param  groupId the primary key of the group
879             * @return the deleted group
880             * @throws PortalException if a portal exception occurred
881             */
882            @Override
883            public Group deleteGroup(long groupId) throws PortalException {
884                    Group group = groupPersistence.findByPrimaryKey(groupId);
885    
886                    return deleteGroup(group);
887            }
888    
889            @Override
890            public synchronized void disableStaging(long groupId)
891                    throws PortalException {
892    
893                    Group group = groupPersistence.findByPrimaryKey(groupId);
894    
895                    int stagingGroupCount = group.getRemoteStagingGroupCount();
896    
897                    if (stagingGroupCount > 0) {
898                            stagingGroupCount = stagingGroupCount - 1;
899    
900                            group.setRemoteStagingGroupCount(stagingGroupCount);
901    
902                            if (stagingGroupCount == 0) {
903                                    UnicodeProperties typeSettingsProperties =
904                                            group.getTypeSettingsProperties();
905    
906                                    List<String> keys = new ArrayList<>();
907    
908                                    for (String key : typeSettingsProperties.keySet()) {
909                                            if (key.startsWith(StagingConstants.STAGED_PORTLET)) {
910                                                    keys.add(key);
911                                            }
912                                    }
913    
914                                    for (String key : keys) {
915                                            typeSettingsProperties.remove(key);
916                                    }
917    
918                                    group.setTypeSettingsProperties(typeSettingsProperties);
919                            }
920    
921                            groupPersistence.update(group);
922                    }
923            }
924    
925            @Override
926            public synchronized void enableStaging(long groupId)
927                    throws PortalException {
928    
929                    Group group = groupPersistence.findByPrimaryKey(groupId);
930    
931                    int stagingGroupCount = group.getRemoteStagingGroupCount() + 1;
932    
933                    group.setRemoteStagingGroupCount(stagingGroupCount);
934    
935                    groupPersistence.update(group);
936            }
937    
938            /**
939             * Returns the company's group.
940             *
941             * @param  companyId the primary key of the company
942             * @return the company's group, or <code>null</code> if a matching group
943             *         could not be found
944             */
945            @Override
946            public Group fetchCompanyGroup(long companyId) {
947                    long classNameId = classNameLocalService.getClassNameId(Company.class);
948    
949                    return groupPersistence.fetchByC_C_C(companyId, classNameId, companyId);
950            }
951    
952            /**
953             * Returns the group with the matching friendly URL.
954             *
955             * @param  companyId the primary key of the company
956             * @param  friendlyURL the friendly URL
957             * @return the group with the friendly URL, or <code>null</code> if a
958             *         matching group could not be found
959             */
960            @Override
961            public Group fetchFriendlyURLGroup(long companyId, String friendlyURL) {
962                    if (Validator.isNull(friendlyURL)) {
963                            return null;
964                    }
965    
966                    friendlyURL = getFriendlyURL(friendlyURL);
967    
968                    return groupPersistence.fetchByC_F(companyId, friendlyURL);
969            }
970    
971            /**
972             * Returns the group with the matching group key by first searching the
973             * system groups and then using the finder cache.
974             *
975             * @param  companyId the primary key of the company
976             * @param  groupKey the group key
977             * @return the group with the group key and associated company, or
978             *         <code>null</code> if a matching group could not be found
979             */
980            @Override
981            @Skip
982            public Group fetchGroup(long companyId, String groupKey) {
983                    Group group = _systemGroupsMap.get(
984                            StringUtil.toHexString(companyId).concat(groupKey));
985    
986                    if (group != null) {
987                            return group;
988                    }
989    
990                    return groupLocalService.loadFetchGroup(companyId, groupKey);
991            }
992    
993            @Override
994            public Group fetchUserGroup(long companyId, long userId) {
995                    long classNameId = classNameLocalService.getClassNameId(User.class);
996    
997                    return groupPersistence.fetchByC_C_C(companyId, classNameId, userId);
998            }
999    
1000            /**
1001             * Returns the default user's personal site group.
1002             *
1003             * @param  companyId the primary key of the company
1004             * @return the default user's personal site group, or <code>null</code> if a
1005             *         matching group could not be found
1006             * @throws PortalException if a portal exception occurred
1007             */
1008            @Override
1009            public Group fetchUserPersonalSiteGroup(long companyId)
1010                    throws PortalException {
1011    
1012                    long classNameId = classNameLocalService.getClassNameId(
1013                            UserPersonalSite.class);
1014                    long defaultUserId = userLocalService.getDefaultUserId(companyId);
1015    
1016                    return groupPersistence.fetchByC_C_C(
1017                            companyId, classNameId, defaultUserId);
1018            }
1019    
1020            /**
1021             * Returns all the active or inactive groups associated with the company.
1022             *
1023             * @param  companyId the primary key of the company
1024             * @param  active whether to return only active groups, or only inactive
1025             *         groups
1026             * @return the active or inactive groups associated with the company
1027             */
1028            @Override
1029            public List<Group> getActiveGroups(long companyId, boolean active) {
1030                    return groupPersistence.findByC_A(companyId, active);
1031            }
1032    
1033            /**
1034             * Returns the company group.
1035             *
1036             * @param  companyId the primary key of the company
1037             * @return the group associated with the company
1038             * @throws PortalException if a portal exception occurred
1039             */
1040            @Override
1041            public Group getCompanyGroup(long companyId) throws PortalException {
1042                    long classNameId = classNameLocalService.getClassNameId(Company.class);
1043    
1044                    return groupPersistence.findByC_C_C(companyId, classNameId, companyId);
1045            }
1046    
1047            /**
1048             * Returns a range of all the groups associated with the company.
1049             *
1050             * <p>
1051             * Useful when paginating results. Returns a maximum of <code>end -
1052             * start</code> instances. <code>start</code> and <code>end</code> are not
1053             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1054             * refers to the first result in the set. Setting both <code>start</code>
1055             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
1056             * result set.
1057             * </p>
1058             *
1059             * @param  companyId the primary key of the company
1060             * @param  start the lower bound of the range of groups to return
1061             * @param  end the upper bound of the range of groups to return (not
1062             *         inclusive)
1063             * @return the range of groups associated with the company
1064             */
1065            @Override
1066            public List<Group> getCompanyGroups(long companyId, int start, int end) {
1067                    return groupPersistence.findByCompanyId(companyId, start, end);
1068            }
1069    
1070            /**
1071             * Returns the number of groups associated with the company.
1072             *
1073             * @param  companyId the primary key of the company
1074             * @return the number of groups associated with the company
1075             */
1076            @Override
1077            public int getCompanyGroupsCount(long companyId) {
1078                    return groupPersistence.countByCompanyId(companyId);
1079            }
1080    
1081            /**
1082             * Returns the group with the matching friendly URL.
1083             *
1084             * @param  companyId the primary key of the company
1085             * @param  friendlyURL the group's friendlyURL
1086             * @return the group with the friendly URL
1087             * @throws PortalException if a portal exception occurred
1088             */
1089            @Override
1090            public Group getFriendlyURLGroup(long companyId, String friendlyURL)
1091                    throws PortalException {
1092    
1093                    if (Validator.isNull(friendlyURL)) {
1094                            StringBundler sb = new StringBundler(5);
1095    
1096                            sb.append("{companyId=");
1097                            sb.append(companyId);
1098                            sb.append(", friendlyURL=");
1099                            sb.append(friendlyURL);
1100                            sb.append("}");
1101    
1102                            throw new NoSuchGroupException(sb.toString());
1103                    }
1104    
1105                    friendlyURL = getFriendlyURL(friendlyURL);
1106    
1107                    return groupPersistence.findByC_F(companyId, friendlyURL);
1108            }
1109    
1110            /**
1111             * Returns the group with the matching primary key.
1112             *
1113             * @param  groupId the primary key of the group
1114             * @return the group with the primary key
1115             * @throws PortalException if a portal exception occurred
1116             */
1117            @Override
1118            @ThreadLocalCachable
1119            public Group getGroup(long groupId) throws PortalException {
1120                    return groupPersistence.findByPrimaryKey(groupId);
1121            }
1122    
1123            /**
1124             * Returns the group with the matching group key.
1125             *
1126             * @param  companyId the primary key of the company
1127             * @param  groupKey the group key
1128             * @return the group with the group key
1129             * @throws PortalException if a portal exception occurred
1130             */
1131            @Override
1132            @Skip
1133            public Group getGroup(long companyId, String groupKey)
1134                    throws PortalException {
1135    
1136                    Group group = _systemGroupsMap.get(
1137                            StringUtil.toHexString(companyId).concat(groupKey));
1138    
1139                    if (group != null) {
1140                            return group;
1141                    }
1142    
1143                    return groupLocalService.loadGetGroup(companyId, groupKey);
1144            }
1145    
1146            /**
1147             * @deprecated As of 7.0.0, replaced by {@link
1148             *             Group#getDescriptiveName(Locale)}
1149             */
1150            @Deprecated
1151            @Override
1152            public String getGroupDescriptiveName(Group group, Locale locale)
1153                    throws PortalException {
1154    
1155                    return group.getDescriptiveName(locale);
1156            }
1157    
1158            /**
1159             * @deprecated As of 7.0.0, replaced by {@link
1160             *             Group#getDescriptiveName(Locale)}
1161             */
1162            @Deprecated
1163            @Override
1164            public String getGroupDescriptiveName(long groupId, Locale locale)
1165                    throws PortalException {
1166    
1167                    Group group = groupPersistence.findByPrimaryKey(groupId);
1168    
1169                    return group.getDescriptiveName(locale);
1170            }
1171    
1172            /**
1173             * Returns all the groups that are direct children of the parent group.
1174             *
1175             * @param  companyId the primary key of the company
1176             * @param  parentGroupId the primary key of the parent group
1177             * @param  site whether the group is to be associated with a main site
1178             * @return the matching groups, or <code>null</code> if no matches were
1179             *         found
1180             */
1181            @Override
1182            public List<Group> getGroups(
1183                    long companyId, long parentGroupId, boolean site) {
1184    
1185                    if (parentGroupId == GroupConstants.ANY_PARENT_GROUP_ID) {
1186                            return groupPersistence.findByC_S(companyId, site);
1187                    }
1188    
1189                    return groupPersistence.findByC_P_S(companyId, parentGroupId, site);
1190            }
1191    
1192            @Override
1193            public List<Group> getGroups(
1194                    long companyId, long parentGroupId, boolean site,
1195                    boolean inheritContent) {
1196    
1197                    return groupPersistence.findByC_P_S_I(
1198                            companyId, parentGroupId, site, inheritContent);
1199            }
1200    
1201            /**
1202             * Returns all the groups that are direct children of the parent group with
1203             * the matching className.
1204             *
1205             * @param  companyId the primary key of the company
1206             * @param  className the class name of the group
1207             * @param  parentGroupId the primary key of the parent group
1208             * @return the matching groups, or <code>null</code> if no matches were
1209             *         found
1210             */
1211            @Override
1212            public List<Group> getGroups(
1213                    long companyId, String className, long parentGroupId) {
1214    
1215                    long classNameId = classNameLocalService.getClassNameId(className);
1216    
1217                    return groupPersistence.findByC_C_P(
1218                            companyId, classNameId, parentGroupId);
1219            }
1220    
1221            /**
1222             * Returns a range of all the groups that are direct children of the parent
1223             * group with the matching className.
1224             *
1225             * @param  companyId the primary key of the company
1226             * @param  className the class name of the group
1227             * @param  parentGroupId the primary key of the parent group
1228             * @param  start the lower bound of the range of results
1229             * @param  end the upper bound of the range of results (not inclusive)
1230             * @return the range of matching groups
1231             */
1232            @Override
1233            public List<Group> getGroups(
1234                    long companyId, String className, long parentGroupId, int start,
1235                    int end) {
1236    
1237                    long classNameId = classNameLocalService.getClassNameId(className);
1238    
1239                    return groupPersistence.findByC_C_P(
1240                            companyId, classNameId, parentGroupId, start, end);
1241            }
1242    
1243            /**
1244             * Returns the groups with the matching primary keys.
1245             *
1246             * @param  groupIds the primary keys of the groups
1247             * @return the groups with the primary keys
1248             * @throws PortalException if a portal exception occurred
1249             */
1250            @Override
1251            public List<Group> getGroups(long[] groupIds) throws PortalException {
1252                    List<Group> groups = new ArrayList<>(groupIds.length);
1253    
1254                    for (long groupId : groupIds) {
1255                            Group group = getGroup(groupId);
1256    
1257                            groups.add(group);
1258                    }
1259    
1260                    return groups;
1261            }
1262    
1263            /**
1264             * Returns the number of groups that are direct children of the parent
1265             * group.
1266             *
1267             * @param  companyId the primary key of the company
1268             * @param  parentGroupId the primary key of the parent group
1269             * @param  site whether the group is to be associated with a main site
1270             * @return the number of matching groups
1271             */
1272            @Override
1273            public int getGroupsCount(
1274                    long companyId, long parentGroupId, boolean site) {
1275    
1276                    if (parentGroupId == GroupConstants.ANY_PARENT_GROUP_ID) {
1277                            return groupPersistence.countByC_S(companyId, site);
1278                    }
1279    
1280                    return groupPersistence.countByC_P_S(companyId, parentGroupId, site);
1281            }
1282    
1283            /**
1284             * Returns the number of groups that are direct children of the parent group
1285             * with the matching className.
1286             *
1287             * @param  companyId the primary key of the company
1288             * @param  className the class name of the group
1289             * @param  parentGroupId the primary key of the parent group
1290             * @return the number of matching groups
1291             */
1292            @Override
1293            public int getGroupsCount(
1294                    long companyId, String className, long parentGroupId) {
1295    
1296                    long classNameId = classNameLocalService.getClassNameId(className);
1297    
1298                    return groupPersistence.countByC_C_P(
1299                            companyId, classNameId, parentGroupId);
1300            }
1301    
1302            /**
1303             * Returns the group associated with the layout.
1304             *
1305             * @param  companyId the primary key of the company
1306             * @param  plid the primary key of the layout
1307             * @return the group associated with the layout
1308             * @throws PortalException if a portal exception occurred
1309             */
1310            @Override
1311            public Group getLayoutGroup(long companyId, long plid)
1312                    throws PortalException {
1313    
1314                    long classNameId = classNameLocalService.getClassNameId(Layout.class);
1315    
1316                    return groupPersistence.findByC_C_C(companyId, classNameId, plid);
1317            }
1318    
1319            /**
1320             * Returns the group associated with the layout prototype.
1321             *
1322             * @param  companyId the primary key of the company
1323             * @param  layoutPrototypeId the primary key of the layout prototype
1324             * @return the group associated with the layout prototype
1325             * @throws PortalException if a portal exception occurred
1326             */
1327            @Override
1328            public Group getLayoutPrototypeGroup(long companyId, long layoutPrototypeId)
1329                    throws PortalException {
1330    
1331                    long classNameId = classNameLocalService.getClassNameId(
1332                            LayoutPrototype.class);
1333    
1334                    return groupPersistence.findByC_C_C(
1335                            companyId, classNameId, layoutPrototypeId);
1336            }
1337    
1338            /**
1339             * Returns the group associated with the layout set prototype.
1340             *
1341             * @param  companyId the primary key of the company
1342             * @param  layoutSetPrototypeId the primary key of the layout set prototype
1343             * @return the group associated with the layout set prototype
1344             * @throws PortalException if a portal exception occurred
1345             */
1346            @Override
1347            public Group getLayoutSetPrototypeGroup(
1348                            long companyId, long layoutSetPrototypeId)
1349                    throws PortalException {
1350    
1351                    long classNameId = classNameLocalService.getClassNameId(
1352                            LayoutSetPrototype.class);
1353    
1354                    return groupPersistence.findByC_C_C(
1355                            companyId, classNameId, layoutSetPrototypeId);
1356            }
1357    
1358            /**
1359             * Returns a range of all groups that are children of the parent group and
1360             * that have at least one layout.
1361             *
1362             * <p>
1363             * Useful when paginating results. Returns a maximum of <code>end -
1364             * start</code> instances. <code>start</code> and <code>end</code> are not
1365             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1366             * refers to the first result in the set. Setting both <code>start</code>
1367             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
1368             * result set.
1369             * </p>
1370             *
1371             * @param  companyId the primary key of the company
1372             * @param  parentGroupId the primary key of the parent group
1373             * @param  site whether the group is to be associated with a main site
1374             * @param  start the lower bound of the range of groups to return
1375             * @param  end the upper bound of the range of groups to return (not
1376             *         inclusive)
1377             * @param  obc the comparator to order the groups (optionally
1378             *         <code>null</code>)
1379             * @return the range of matching groups ordered by comparator
1380             *         <code>obc</code>
1381             */
1382            @Override
1383            public List<Group> getLayoutsGroups(
1384                    long companyId, long parentGroupId, boolean site, int start, int end,
1385                    OrderByComparator<Group> obc) {
1386    
1387                    return groupFinder.findByLayouts(
1388                            companyId, parentGroupId, site, start, end, obc);
1389            }
1390    
1391            /**
1392             * Returns the number of groups that are children or the parent group and
1393             * that have at least one layout
1394             *
1395             * @param  companyId the primary key of the company
1396             * @param  parentGroupId the primary key of the parent group
1397             * @param  site whether the group is to be associated with a main site
1398             * @return the number of matching groups
1399             */
1400            @Override
1401            public int getLayoutsGroupsCount(
1402                    long companyId, long parentGroupId, boolean site) {
1403    
1404                    return groupFinder.countByLayouts(companyId, parentGroupId, site);
1405            }
1406    
1407            /**
1408             * Returns all live groups.
1409             *
1410             * @return all live groups
1411             */
1412            @Override
1413            public List<Group> getLiveGroups() {
1414                    return groupFinder.findByLiveGroups();
1415            }
1416    
1417            /**
1418             * Returns a range of all non-system groups of a specified type (className)
1419             * that have no layouts.
1420             *
1421             * <p>
1422             * Useful when paginating results. Returns a maximum of <code>end -
1423             * start</code> instances. <code>start</code> and <code>end</code> are not
1424             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1425             * refers to the first result in the set. Setting both <code>start</code>
1426             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
1427             * result set.
1428             * </p>
1429             *
1430             * @param  className the entity's class name
1431             * @param  privateLayout whether to include groups with private layout sets
1432             *         or non-private layout sets
1433             * @param  start the lower bound of the range of groups to return
1434             * @param  end the upper bound of the range of groups to return (not
1435             *         inclusive)
1436             * @return the range of matching groups
1437             */
1438            @Override
1439            public List<Group> getNoLayoutsGroups(
1440                    String className, boolean privateLayout, int start, int end) {
1441    
1442                    long classNameId = classNameLocalService.getClassNameId(className);
1443    
1444                    return groupFinder.findByNoLayouts(
1445                            classNameId, privateLayout, start, end);
1446            }
1447    
1448            /**
1449             * Returns all non-system groups having <code>null</code> or empty friendly
1450             * URLs.
1451             *
1452             * @return the non-system groups having <code>null</code> or empty friendly
1453             *         URLs
1454             */
1455            @Override
1456            public List<Group> getNullFriendlyURLGroups() {
1457                    return groupFinder.findByNullFriendlyURL();
1458            }
1459    
1460            /**
1461             * Returns the specified organization group.
1462             *
1463             * @param  companyId the primary key of the company
1464             * @param  organizationId the primary key of the organization
1465             * @return the group associated with the organization
1466             * @throws PortalException if a portal exception occurred
1467             */
1468            @Override
1469            public Group getOrganizationGroup(long companyId, long organizationId)
1470                    throws PortalException {
1471    
1472                    long classNameId = classNameLocalService.getClassNameId(
1473                            Organization.class);
1474    
1475                    return groupPersistence.findByC_C_C(
1476                            companyId, classNameId, organizationId);
1477            }
1478    
1479            /**
1480             * Returns the specified organization groups.
1481             *
1482             * @param  organizations the organizations
1483             * @return the groups associated with the organizations
1484             */
1485            @Override
1486            public List<Group> getOrganizationsGroups(
1487                    List<Organization> organizations) {
1488    
1489                    List<Group> organizationGroups = new ArrayList<>();
1490    
1491                    for (int i = 0; i < organizations.size(); i++) {
1492                            Organization organization = organizations.get(i);
1493    
1494                            Group group = organization.getGroup();
1495    
1496                            organizationGroups.add(group);
1497                    }
1498    
1499                    return organizationGroups;
1500            }
1501    
1502            /**
1503             * Returns all the groups related to the organizations.
1504             *
1505             * @param  organizations the organizations
1506             * @return the groups related to the organizations
1507             */
1508            @Override
1509            public List<Group> getOrganizationsRelatedGroups(
1510                    List<Organization> organizations) {
1511    
1512                    List<Group> organizationGroups = new ArrayList<>();
1513    
1514                    for (int i = 0; i < organizations.size(); i++) {
1515                            Organization organization = organizations.get(i);
1516    
1517                            List<Group> groups = organizationPersistence.getGroups(
1518                                    organization.getOrganizationId());
1519    
1520                            organizationGroups.addAll(groups);
1521                    }
1522    
1523                    return organizationGroups;
1524            }
1525    
1526            /**
1527             * Returns the group followed by all its parent groups ordered by closest
1528             * ancestor.
1529             *
1530             * @param  groupId the primary key of the group
1531             * @return the group followed by all its parent groups ordered by closest
1532             *         ancestor
1533             * @throws PortalException if a portal exception occurred
1534             */
1535            @Override
1536            public List<Group> getParentGroups(long groupId) throws PortalException {
1537                    if (groupId == GroupConstants.DEFAULT_PARENT_GROUP_ID) {
1538                            return new ArrayList<>();
1539                    }
1540    
1541                    Group group = groupPersistence.findByPrimaryKey(groupId);
1542    
1543                    return group.getAncestors();
1544            }
1545    
1546            /**
1547             * Returns the staging group.
1548             *
1549             * @param  liveGroupId the primary key of the live group
1550             * @return the staging group
1551             * @throws PortalException if a portal exception occurred
1552             */
1553            @Override
1554            public Group getStagingGroup(long liveGroupId) throws PortalException {
1555                    return groupPersistence.findByLiveGroupId(liveGroupId);
1556            }
1557    
1558            /**
1559             * Returns the group directly associated with the user.
1560             *
1561             * @param  companyId the primary key of the company
1562             * @param  userId the primary key of the user
1563             * @return the group directly associated with the user
1564             * @throws PortalException if a portal exception occurred
1565             */
1566            @Override
1567            public Group getUserGroup(long companyId, long userId)
1568                    throws PortalException {
1569    
1570                    long classNameId = classNameLocalService.getClassNameId(User.class);
1571    
1572                    return groupPersistence.findByC_C_C(companyId, classNameId, userId);
1573            }
1574    
1575            /**
1576             * Returns the specified "user group" group. That is, the group that
1577             * represents the {@link UserGroup} entity.
1578             *
1579             * @param  companyId the primary key of the company
1580             * @param  userGroupId the primary key of the user group
1581             * @return the group associated with the user group
1582             * @throws PortalException if a portal exception occurred
1583             */
1584            @Override
1585            public Group getUserGroupGroup(long companyId, long userGroupId)
1586                    throws PortalException {
1587    
1588                    long classNameId = classNameLocalService.getClassNameId(
1589                            UserGroup.class);
1590    
1591                    return groupPersistence.findByC_C_C(
1592                            companyId, classNameId, userGroupId);
1593            }
1594    
1595            /**
1596             * Returns all the user's site groups and immediate organization groups,
1597             * optionally including the user's inherited organization groups and user
1598             * groups. System and staged groups are not included.
1599             *
1600             * @param  userId the primary key of the user
1601             * @param  inherit whether to include the user's inherited organization
1602             *         groups and user groups
1603             * @return the user's groups and immediate organization groups
1604             * @throws PortalException if a portal exception occurred
1605             */
1606            @Override
1607            public List<Group> getUserGroups(long userId, boolean inherit)
1608                    throws PortalException {
1609    
1610                    return getUserGroups(
1611                            userId, inherit, QueryUtil.ALL_POS, QueryUtil.ALL_POS);
1612            }
1613    
1614            /**
1615             * Returns an ordered range of all the user's site groups and immediate
1616             * organization groups, optionally including the user's inherited
1617             * organization groups and user groups. System and staged groups are not
1618             * included.
1619             *
1620             * <p>
1621             * Useful when paginating results. Returns a maximum of <code>end -
1622             * start</code> instances. <code>start</code> and <code>end</code> are not
1623             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1624             * refers to the first result in the set. Setting both <code>start</code>
1625             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
1626             * result set.
1627             * </p>
1628             *
1629             * @param  userId the primary key of the user
1630             * @param  inherit whether to include the user's inherited organization
1631             *         groups and user groups
1632             * @param  start the lower bound of the range of groups to return
1633             * @param  end the upper bound of the range of groups to return (not
1634             *         inclusive)
1635             * @return the range of the user's groups and immediate organization groups
1636             *         ordered by name
1637             * @throws PortalException if a portal exception occurred
1638             */
1639            @Override
1640            public List<Group> getUserGroups(
1641                            long userId, boolean inherit, int start, int end)
1642                    throws PortalException {
1643    
1644                    if (inherit) {
1645                            User user = userPersistence.findByPrimaryKey(userId);
1646    
1647                            LinkedHashMap<String, Object> groupParams = new LinkedHashMap<>();
1648    
1649                            groupParams.put("usersGroups", Long.valueOf(userId));
1650    
1651                            return search(
1652                                    user.getCompanyId(), null, null, groupParams, start, end);
1653                    }
1654                    else {
1655                            return userPersistence.getGroups(userId, start, end);
1656                    }
1657            }
1658    
1659            /**
1660             * Returns the groups associated with the user groups.
1661             *
1662             * @param  userGroups the user groups
1663             * @return the groups associated with the user groups
1664             * @throws PortalException if a portal exception occurred
1665             */
1666            @Override
1667            public List<Group> getUserGroupsGroups(List<UserGroup> userGroups)
1668                    throws PortalException {
1669    
1670                    List<Group> userGroupGroups = new ArrayList<>();
1671    
1672                    for (int i = 0; i < userGroups.size(); i++) {
1673                            UserGroup userGroup = userGroups.get(i);
1674    
1675                            Group group = userGroup.getGroup();
1676    
1677                            userGroupGroups.add(group);
1678                    }
1679    
1680                    return userGroupGroups;
1681            }
1682    
1683            /**
1684             * Returns all the groups related to the user groups.
1685             *
1686             * @param  userGroups the user groups
1687             * @return the groups related to the user groups
1688             */
1689            @Override
1690            public List<Group> getUserGroupsRelatedGroups(List<UserGroup> userGroups) {
1691                    List<Group> userGroupGroups = new ArrayList<>();
1692    
1693                    for (int i = 0; i < userGroups.size(); i++) {
1694                            UserGroup userGroup = userGroups.get(i);
1695    
1696                            List<Group> groups = userGroupPersistence.getGroups(
1697                                    userGroup.getUserGroupId());
1698    
1699                            userGroupGroups.addAll(groups);
1700                    }
1701    
1702                    return userGroupGroups;
1703            }
1704    
1705            /**
1706             * Returns the range of all groups associated with the user's organization
1707             * groups, including the ancestors of the organization groups, unless portal
1708             * property <code>organizations.membership.strict</code> is set to
1709             * <code>true</code>.
1710             *
1711             * <p>
1712             * Useful when paginating results. Returns a maximum of <code>end -
1713             * start</code> instances. <code>start</code> and <code>end</code> are not
1714             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1715             * refers to the first result in the set. Setting both <code>start</code>
1716             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
1717             * result set.
1718             * </p>
1719             *
1720             * @param  userId the primary key of the user
1721             * @param  start the lower bound of the range of groups to consider
1722             * @param  end the upper bound of the range of groups to consider (not
1723             *         inclusive)
1724             * @return the range of groups associated with the user's organization
1725             *         groups
1726             * @throws PortalException if a portal exception occurred
1727             */
1728            @Override
1729            public List<Group> getUserOrganizationsGroups(
1730                            long userId, int start, int end)
1731                    throws PortalException {
1732    
1733                    List<Group> userOrgsGroups = new ArrayList<>();
1734    
1735                    List<Organization> userOrgs =
1736                            organizationLocalService.getUserOrganizations(userId, start, end);
1737    
1738                    for (Organization organization : userOrgs) {
1739                            userOrgsGroups.add(0, organization.getGroup());
1740    
1741                            if (!PropsValues.ORGANIZATIONS_MEMBERSHIP_STRICT) {
1742                                    for (Organization ancestorOrganization :
1743                                                    organization.getAncestors()) {
1744    
1745                                            userOrgsGroups.add(0, ancestorOrganization.getGroup());
1746                                    }
1747                            }
1748                    }
1749    
1750                    return ListUtil.unique(userOrgsGroups);
1751            }
1752    
1753            /**
1754             * Returns the default user's personal site group.
1755             *
1756             * @param  companyId the primary key of the company
1757             * @return the default user's personal site group
1758             * @throws PortalException if a portal exception occurred
1759             */
1760            @Override
1761            public Group getUserPersonalSiteGroup(long companyId)
1762                    throws PortalException {
1763    
1764                    long classNameId = classNameLocalService.getClassNameId(
1765                            UserPersonalSite.class);
1766                    long defaultUserId = userLocalService.getDefaultUserId(companyId);
1767    
1768                    return groupPersistence.findByC_C_C(
1769                            companyId, classNameId, defaultUserId);
1770            }
1771    
1772            @Override
1773            public List<Group> getUserSitesGroups(long userId) throws PortalException {
1774                    User user = userPersistence.findByPrimaryKey(userId);
1775    
1776                    LinkedHashMap<String, Object> groupParams = new LinkedHashMap<>();
1777    
1778                    groupParams.put("inherit", Boolean.TRUE);
1779                    groupParams.put("site", Boolean.TRUE);
1780                    groupParams.put("usersGroups", userId);
1781    
1782                    return groupFinder.findByCompanyId(
1783                            user.getCompanyId(), groupParams, QueryUtil.ALL_POS,
1784                            QueryUtil.ALL_POS, new GroupNameComparator(true));
1785            }
1786    
1787            @Override
1788            public List<Group> getUserSitesGroups(
1789                            long userId, boolean includeAdministrative)
1790                    throws PortalException {
1791    
1792                    if (!includeAdministrative) {
1793                            return getUserSitesGroups(userId);
1794                    }
1795    
1796                    Set<Group> sites = new HashSet<>();
1797    
1798                    List<UserGroupRole> userGroupRoles =
1799                            userGroupRoleLocalService.getUserGroupRoles(userId);
1800    
1801                    for (UserGroupRole userGroupRole : userGroupRoles) {
1802                            Role role = userGroupRole.getRole();
1803    
1804                            String roleName = role.getName();
1805    
1806                            if (roleName.equals(RoleConstants.SITE_ADMINISTRATOR) ||
1807                                    roleName.equals(RoleConstants.SITE_OWNER)) {
1808    
1809                                    Group group = userGroupRole.getGroup();
1810    
1811                                    sites.add(group);
1812                            }
1813                    }
1814    
1815                    sites.addAll(getUserSitesGroups(userId));
1816    
1817                    return new ArrayList<>(sites);
1818            }
1819    
1820            /**
1821             * Returns <code>true</code> if the live group has a staging group.
1822             *
1823             * @param  liveGroupId the primary key of the live group
1824             * @return <code>true</code> if the live group has a staging group;
1825             *         <code>false</code> otherwise
1826             */
1827            @Override
1828            public boolean hasStagingGroup(long liveGroupId) {
1829                    if (groupPersistence.fetchByLiveGroupId(liveGroupId) != null) {
1830                            return true;
1831                    }
1832                    else {
1833                            return false;
1834                    }
1835            }
1836    
1837            /**
1838             * Returns <code>true</code> if the user is immediately associated with the
1839             * group, or associated with the group via the user's organizations,
1840             * inherited organizations, or user groups.
1841             *
1842             * @param  userId the primary key of the user
1843             * @param  groupId the primary key of the group
1844             * @return <code>true</code> if the user is associated with the group;
1845             *         <code>false</code> otherwise
1846             */
1847            @Override
1848            public boolean hasUserGroup(long userId, long groupId) {
1849                    return hasUserGroup(userId, groupId, true);
1850            }
1851    
1852            /**
1853             * Returns <code>true</code> if the user is immediately associated with the
1854             * group, or optionally if the user is associated with the group via the
1855             * user's organizations, inherited organizations, or user groups.
1856             *
1857             * @param  userId the primary key of the user
1858             * @param  groupId the primary key of the group
1859             * @param  inherit whether to include organization groups and user groups to
1860             *         which the user belongs in the determination
1861             * @return <code>true</code> if the user is associated with the group;
1862             *         <code>false</code> otherwise
1863             */
1864            @Override
1865            public boolean hasUserGroup(long userId, long groupId, boolean inherit) {
1866                    if (groupFinder.countByG_U(groupId, userId, inherit) > 0) {
1867                            return true;
1868                    }
1869                    else {
1870                            return false;
1871                    }
1872            }
1873    
1874            /**
1875             * Returns the group with the matching group key by first searching the
1876             * system groups and then using the finder cache.
1877             *
1878             * @param  companyId the primary key of the company
1879             * @param  groupKey the group key
1880             * @return the group with the group key and associated company, or
1881             *         <code>null</code> if a matching group could not be found
1882             */
1883            @Override
1884            public Group loadFetchGroup(long companyId, String groupKey) {
1885                    return groupPersistence.fetchByC_GK(companyId, groupKey);
1886            }
1887    
1888            /**
1889             * Returns the group with the matching group key.
1890             *
1891             * @param  companyId the primary key of the company
1892             * @param  groupKey the group key
1893             * @return the group with the group key and associated company
1894             * @throws PortalException if a portal exception occurred
1895             */
1896            @Override
1897            public Group loadGetGroup(long companyId, String groupKey)
1898                    throws PortalException {
1899    
1900                    return groupPersistence.findByC_GK(companyId, groupKey);
1901            }
1902    
1903            /**
1904             * Rebuilds the group tree.
1905             *
1906             * <p>
1907             * Only call this method if the tree has become stale through operations
1908             * other than normal CRUD. Under normal circumstances the tree is
1909             * automatically rebuilt whenever necessary.
1910             * </p>
1911             *
1912             * @param  companyId the primary key of the group's company
1913             * @throws PortalException if a portal exception occurred
1914             */
1915            @Override
1916            public void rebuildTree(long companyId) throws PortalException {
1917                    TreePathUtil.rebuildTree(
1918                            companyId, GroupConstants.DEFAULT_PARENT_GROUP_ID, StringPool.SLASH,
1919                            new TreeModelTasksAdapter<Group>() {
1920    
1921                                    @Override
1922                                    public List<Group> findTreeModels(
1923                                            long previousId, long companyId, long parentPrimaryKey,
1924                                            int size) {
1925    
1926                                            return groupPersistence.findByG_C_P(
1927                                                    previousId, companyId, parentPrimaryKey,
1928                                                    QueryUtil.ALL_POS, size, new GroupIdComparator(true));
1929                                    }
1930    
1931                            }
1932                    );
1933            }
1934    
1935            /**
1936             * Returns an ordered range of all the company's groups, optionally
1937             * including the user's inherited organization groups and user groups.
1938             * System and staged groups are not included.
1939             *
1940             * <p>
1941             * Useful when paginating results. Returns a maximum of <code>end -
1942             * start</code> instances. <code>start</code> and <code>end</code> are not
1943             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1944             * refers to the first result in the set. Setting both <code>start</code>
1945             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
1946             * result set.
1947             * </p>
1948             *
1949             * @param  companyId the primary key of the company
1950             * @param  params the finder params (optionally <code>null</code>). To
1951             *         include a user's organizations, inherited organizations, and user
1952             *         groups in the search, add an entry with key
1953             *         &quot;usersGroups&quot; mapped to the user's ID and an entry with
1954             *         key &quot;inherit&quot; mapped to a non-<code>null</code> object.
1955             *         For more information see {@link
1956             *         com.liferay.portal.service.persistence.GroupFinder}.
1957             * @param  start the lower bound of the range of groups to return
1958             * @param  end the upper bound of the range of groups to return (not
1959             *         inclusive)
1960             * @return the matching groups ordered by name
1961             */
1962            @Override
1963            public List<Group> search(
1964                    long companyId, LinkedHashMap<String, Object> params, int start,
1965                    int end) {
1966    
1967                    return groupFinder.findByCompanyId(
1968                            companyId, params, start, end, new GroupNameComparator(true));
1969            }
1970    
1971            /**
1972             * Returns an ordered range of all the groups belonging to the parent group
1973             * that match the keywords, optionally including the user's inherited
1974             * organization groups and user groups. System and staged groups are not
1975             * included.
1976             *
1977             * <p>
1978             * Useful when paginating results. Returns a maximum of <code>end -
1979             * start</code> instances. <code>start</code> and <code>end</code> are not
1980             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1981             * refers to the first result in the set. Setting both <code>start</code>
1982             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
1983             * result set.
1984             * </p>
1985             *
1986             * @param  companyId the primary key of the company
1987             * @param  parentGroupId the primary key of the parent group
1988             * @param  keywords the keywords (space separated), which may occur in the
1989             *         sites's name, or description (optionally <code>null</code>)
1990             * @param  params the finder params (optionally <code>null</code>). To
1991             *         include the user's inherited organizations and user groups in the
1992             *         search, add entries having &quot;usersGroups&quot; and
1993             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
1994             *         information see {@link
1995             *         com.liferay.portal.service.persistence.GroupFinder}.
1996             * @param  start the lower bound of the range of groups to return
1997             * @param  end the upper bound of the range of groups to return (not
1998             *         inclusive)
1999             * @return the matching groups ordered by name
2000             */
2001            @Override
2002            public List<Group> search(
2003                    long companyId, long parentGroupId, String keywords,
2004                    LinkedHashMap<String, Object> params, int start, int end) {
2005    
2006                    return search(
2007                            companyId, getClassNameIds(), parentGroupId, keywords, params,
2008                            start, end, null);
2009            }
2010    
2011            /**
2012             * Returns an ordered range of all the groups belonging to the parent group
2013             * that match the keywords, optionally including the user's inherited
2014             * organization groups and user groups. System and staged groups are not
2015             * included.
2016             *
2017             * <p>
2018             * Useful when paginating results. Returns a maximum of <code>end -
2019             * start</code> instances. <code>start</code> and <code>end</code> are not
2020             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2021             * refers to the first result in the set. Setting both <code>start</code>
2022             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2023             * result set.
2024             * </p>
2025             *
2026             * @param  companyId the primary key of the company
2027             * @param  parentGroupId the primary key of the parent group
2028             * @param  keywords the keywords (space separated), which may occur in the
2029             *         sites's name, or description (optionally <code>null</code>)
2030             * @param  params the finder params (optionally <code>null</code>). To
2031             *         include the user's inherited organizations and user groups in the
2032             *         search, add entries having &quot;usersGroups&quot; and
2033             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2034             *         information see {@link
2035             *         com.liferay.portal.service.persistence.GroupFinder}.
2036             * @param  start the lower bound of the range of groups to return
2037             * @param  end the upper bound of the range of groups to return (not
2038             *         inclusive)
2039             * @param  obc the comparator to order the groups (optionally
2040             *         <code>null</code>)
2041             * @return the matching groups ordered by comparator <code>obc</code>
2042             */
2043            @Override
2044            public List<Group> search(
2045                    long companyId, long parentGroupId, String keywords,
2046                    LinkedHashMap<String, Object> params, int start, int end,
2047                    OrderByComparator<Group> obc) {
2048    
2049                    return search(
2050                            companyId, getClassNameIds(), parentGroupId, keywords, params,
2051                            start, end, obc);
2052            }
2053    
2054            /**
2055             * Returns an ordered range of all the site groups belonging to the parent
2056             * group and organization groups that match the name and description,
2057             * optionally including the user's inherited organization groups and user
2058             * groups. System and staged groups are not included.
2059             *
2060             * <p>
2061             * Useful when paginating results. Returns a maximum of <code>end -
2062             * start</code> instances. <code>start</code> and <code>end</code> are not
2063             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2064             * refers to the first result in the set. Setting both <code>start</code>
2065             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2066             * result set.
2067             * </p>
2068             *
2069             * @param  companyId the primary key of the company
2070             * @param  parentGroupId the primary key of the parent group
2071             * @param  name the group's name (optionally <code>null</code>)
2072             * @param  description the group's description (optionally
2073             *         <code>null</code>)
2074             * @param  params the finder params (optionally <code>null</code>). To
2075             *         include the user's inherited organizations and user groups in the
2076             *         search, add entries having &quot;usersGroups&quot; and
2077             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2078             *         information see {@link
2079             *         com.liferay.portal.service.persistence.GroupFinder}.
2080             * @param  andOperator whether every field must match its keywords, or just
2081             *         one field.
2082             * @param  start the lower bound of the range of groups to return
2083             * @param  end the upper bound of the range of groups to return (not
2084             *         inclusive)
2085             * @return the matching groups ordered by name
2086             */
2087            @Override
2088            public List<Group> search(
2089                    long companyId, long parentGroupId, String name, String description,
2090                    LinkedHashMap<String, Object> params, boolean andOperator, int start,
2091                    int end) {
2092    
2093                    return search(
2094                            companyId, getClassNameIds(), parentGroupId, name, description,
2095                            params, andOperator, start, end, null);
2096            }
2097    
2098            /**
2099             * Returns an ordered range of all the site groups belonging to the parent
2100             * group and organization groups that match the name and description,
2101             * optionally including the user's inherited organization groups and user
2102             * groups. System and staged groups are not included.
2103             *
2104             * <p>
2105             * Useful when paginating results. Returns a maximum of <code>end -
2106             * start</code> instances. <code>start</code> and <code>end</code> are not
2107             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2108             * refers to the first result in the set. Setting both <code>start</code>
2109             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2110             * result set.
2111             * </p>
2112             *
2113             * @param  companyId the primary key of the company
2114             * @param  parentGroupId the primary key of the parent group
2115             * @param  name the group's name (optionally <code>null</code>)
2116             * @param  description the group's description (optionally
2117             *         <code>null</code>)
2118             * @param  params the finder params (optionally <code>null</code>). To
2119             *         include the user's inherited organizations and user groups in the
2120             *         search, add entries having &quot;usersGroups&quot; and
2121             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2122             *         information see {@link
2123             *         com.liferay.portal.service.persistence.GroupFinder}.
2124             * @param  andOperator whether every field must match its keywords, or just
2125             *         one field.
2126             * @param  start the lower bound of the range of groups to return
2127             * @param  end the upper bound of the range of groups to return (not
2128             *         inclusive)
2129             * @param  obc the comparator to order the groups (optionally
2130             *         <code>null</code>)
2131             * @return the matching groups ordered by comparator <code>obc</code>
2132             */
2133            @Override
2134            public List<Group> search(
2135                    long companyId, long parentGroupId, String name, String description,
2136                    LinkedHashMap<String, Object> params, boolean andOperator, int start,
2137                    int end, OrderByComparator<Group> obc) {
2138    
2139                    return search(
2140                            companyId, getClassNameIds(), parentGroupId, name, description,
2141                            params, andOperator, start, end, obc);
2142            }
2143    
2144            /**
2145             * Returns an ordered range of all the groups belonging to the parent group
2146             * that match the class name IDs and keywords, optionally including the
2147             * user's inherited organization groups and user groups. System and staged
2148             * groups are not included.
2149             *
2150             * <p>
2151             * Useful when paginating results. Returns a maximum of <code>end -
2152             * start</code> instances. <code>start</code> and <code>end</code> are not
2153             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2154             * refers to the first result in the set. Setting both <code>start</code>
2155             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2156             * result set.
2157             * </p>
2158             *
2159             * @param  companyId the primary key of the company
2160             * @param  classNameIds the primary keys of the class names of the entities
2161             *         the groups are related to (optionally <code>null</code>)
2162             * @param  parentGroupId the primary key of the parent group
2163             * @param  keywords the keywords (space separated), which may occur in the
2164             *         sites's name, or description (optionally <code>null</code>)
2165             * @param  params the finder params (optionally <code>null</code>). To
2166             *         include a user's organizations, inherited organizations, and user
2167             *         groups in the search, add an entry with key
2168             *         &quot;usersGroups&quot; mapped to the user's ID and an entry with
2169             *         key &quot;inherit&quot; mapped to a non-<code>null</code> object.
2170             *         For more information see {@link
2171             *         com.liferay.portal.service.persistence.GroupFinder}.
2172             * @param  start the lower bound of the range of groups to return
2173             * @param  end the upper bound of the range of groups to return (not
2174             *         inclusive)
2175             * @return the matching groups ordered by name
2176             */
2177            @Override
2178            public List<Group> search(
2179                    long companyId, long[] classNameIds, long parentGroupId,
2180                    String keywords, LinkedHashMap<String, Object> params, int start,
2181                    int end) {
2182    
2183                    return search(
2184                            companyId, classNameIds, parentGroupId, keywords, params, start,
2185                            end, null);
2186            }
2187    
2188            /**
2189             * Returns an ordered range of all the groups belonging to the parent group
2190             * that match the class name IDs and keywords, optionally including the
2191             * user's inherited organization groups and user groups. System and staged
2192             * groups are not included.
2193             *
2194             * <p>
2195             * Useful when paginating results. Returns a maximum of <code>end -
2196             * start</code> instances. <code>start</code> and <code>end</code> are not
2197             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2198             * refers to the first result in the set. Setting both <code>start</code>
2199             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2200             * result set.
2201             * </p>
2202             *
2203             * @param  companyId the primary key of the company
2204             * @param  classNameIds the primary keys of the class names of the entities
2205             *         the groups are related to (optionally <code>null</code>)
2206             * @param  parentGroupId the primary key of the parent group
2207             * @param  keywords the keywords (space separated), which may occur in the
2208             *         sites's name, or description (optionally <code>null</code>)
2209             * @param  params the finder params (optionally <code>null</code>). To
2210             *         include a user's organizations, inherited organizations, and user
2211             *         groups in the search, add an entry with key
2212             *         &quot;usersGroups&quot; mapped to the user's ID and an entry with
2213             *         key &quot;inherit&quot; mapped to a non-<code>null</code> object.
2214             *         For more information see {@link
2215             *         com.liferay.portal.service.persistence.GroupFinder}.
2216             * @param  start the lower bound of the range of groups to return
2217             * @param  end the upper bound of the range of groups to return (not
2218             *         inclusive)
2219             * @param  obc the comparator to order the groups (optionally
2220             *         <code>null</code>)
2221             * @return the matching groups ordered by comparator <code>obc</code>
2222             */
2223            @Override
2224            public List<Group> search(
2225                    long companyId, long[] classNameIds, long parentGroupId,
2226                    String keywords, LinkedHashMap<String, Object> params, int start,
2227                    int end, OrderByComparator<Group> obc) {
2228    
2229                    String[] keywordsArray = getSearchNames(companyId, keywords);
2230    
2231                    boolean andOperator = false;
2232    
2233                    if (Validator.isNull(keywords)) {
2234                            andOperator = true;
2235                    }
2236    
2237                    if (isUseComplexSQL(classNameIds)) {
2238                            return groupFinder.findByC_C_PG_N_D(
2239                                    companyId, classNameIds, parentGroupId, keywordsArray,
2240                                    keywordsArray, params, andOperator, start, end, obc);
2241                    }
2242    
2243                    Collection<Group> groups = doSearch(
2244                            companyId, classNameIds, parentGroupId, keywordsArray,
2245                            keywordsArray, params, andOperator);
2246    
2247                    return sort(groups, start, end, obc);
2248            }
2249    
2250            /**
2251             * Returns an ordered range of all the groups belonging to the parent group
2252             * that match the class name IDs, name, and description, optionally
2253             * including the user's inherited organization groups and user groups.
2254             * System and staged groups are not included.
2255             *
2256             * <p>
2257             * Useful when paginating results. Returns a maximum of <code>end -
2258             * start</code> instances. <code>start</code> and <code>end</code> are not
2259             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2260             * refers to the first result in the set. Setting both <code>start</code>
2261             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2262             * result set.
2263             * </p>
2264             *
2265             * @param  companyId the primary key of the company
2266             * @param  classNameIds the primary keys of the class names of the entities
2267             *         the groups are related to (optionally <code>null</code>)
2268             * @param  parentGroupId the primary key of the parent group
2269             * @param  name the group's name (optionally <code>null</code>)
2270             * @param  description the group's description (optionally
2271             *         <code>null</code>)
2272             * @param  params the finder params (optionally <code>null</code>). To
2273             *         include a user's organizations, inherited organizations, and user
2274             *         groups in the search, add an entry with key
2275             *         &quot;usersGroups&quot; mapped to the user's ID and an entry with
2276             *         key &quot;inherit&quot; mapped to a non-<code>null</code> object.
2277             *         For more information see {@link
2278             *         com.liferay.portal.service.persistence.GroupFinder}.
2279             * @param  andOperator whether every field must match its keywords, or just
2280             *         one field.
2281             * @param  start the lower bound of the range of groups to return
2282             * @param  end the upper bound of the range of groups to return (not
2283             *         inclusive)
2284             * @return the matching groups ordered by name
2285             */
2286            @Override
2287            public List<Group> search(
2288                    long companyId, long[] classNameIds, long parentGroupId, String name,
2289                    String description, LinkedHashMap<String, Object> params,
2290                    boolean andOperator, int start, int end) {
2291    
2292                    return search(
2293                            companyId, classNameIds, parentGroupId, name, description, params,
2294                            andOperator, start, end, null);
2295            }
2296    
2297            /**
2298             * Returns an ordered range of all the groups belonging to the parent group
2299             * that match the class name IDs, name, and description, optionally
2300             * including the user's inherited organization groups and user groups.
2301             * System and staged groups are not included.
2302             *
2303             * <p>
2304             * Useful when paginating results. Returns a maximum of <code>end -
2305             * start</code> instances. <code>start</code> and <code>end</code> are not
2306             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2307             * refers to the first result in the set. Setting both <code>start</code>
2308             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2309             * result set.
2310             * </p>
2311             *
2312             * @param  companyId the primary key of the company
2313             * @param  classNameIds the primary keys of the class names of the entities
2314             *         the groups are related to (optionally <code>null</code>)
2315             * @param  parentGroupId the primary key of the parent group
2316             * @param  name the group's name (optionally <code>null</code>)
2317             * @param  description the group's description (optionally
2318             *         <code>null</code>)
2319             * @param  params the finder params (optionally <code>null</code>). To
2320             *         include a user's organizations, inherited organizations, and user
2321             *         groups in the search, add an entry with key
2322             *         &quot;usersGroups&quot; mapped to the user's ID and an entry with
2323             *         key &quot;inherit&quot; mapped to a non-<code>null</code> object.
2324             *         For more information see {@link
2325             *         com.liferay.portal.service.persistence.GroupFinder}.
2326             * @param  andOperator whether every field must match its keywords, or just
2327             *         one field.
2328             * @param  start the lower bound of the range of groups to return
2329             * @param  end the upper bound of the range of groups to return (not
2330             *         inclusive)
2331             * @param  obc the comparator to order the groups (optionally
2332             *         <code>null</code>)
2333             * @return the matching groups ordered by comparator <code>obc</code>
2334             */
2335            @Override
2336            public List<Group> search(
2337                    long companyId, long[] classNameIds, long parentGroupId, String name,
2338                    String description, LinkedHashMap<String, Object> params,
2339                    boolean andOperator, int start, int end, OrderByComparator<Group> obc) {
2340    
2341                    String[] names = getSearchNames(companyId, name);
2342                    String[] descriptions = CustomSQLUtil.keywords(description);
2343    
2344                    if (isUseComplexSQL(classNameIds)) {
2345                            return groupFinder.findByC_C_PG_N_D(
2346                                    companyId, classNameIds, parentGroupId, names, descriptions,
2347                                    params, andOperator, start, end, obc);
2348                    }
2349    
2350                    Collection<Group> groups = doSearch(
2351                            companyId, classNameIds, parentGroupId, names, descriptions, params,
2352                            andOperator);
2353    
2354                    return sort(groups, start, end, obc);
2355            }
2356    
2357            /**
2358             * Returns an ordered range of all the groups that match the class name IDs
2359             * and keywords, optionally including the user's inherited organization
2360             * groups and user groups. System and staged groups are not included.
2361             *
2362             * <p>
2363             * Useful when paginating results. Returns a maximum of <code>end -
2364             * start</code> instances. <code>start</code> and <code>end</code> are not
2365             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2366             * refers to the first result in the set. Setting both <code>start</code>
2367             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2368             * result set.
2369             * </p>
2370             *
2371             * @param  companyId the primary key of the company
2372             * @param  classNameIds the primary keys of the class names of the entities
2373             *         the groups are related to (optionally <code>null</code>)
2374             * @param  keywords the keywords (space separated), which may occur in the
2375             *         sites's name, or description (optionally <code>null</code>)
2376             * @param  params the finder params (optionally <code>null</code>). To
2377             *         include a user's organizations, inherited organizations, and user
2378             *         groups in the search, add an entry with key
2379             *         &quot;usersGroups&quot; mapped to the user's ID and an entry with
2380             *         key &quot;inherit&quot; mapped to a non-<code>null</code> object.
2381             *         For more information see {@link
2382             *         com.liferay.portal.service.persistence.GroupFinder}.
2383             * @param  start the lower bound of the range of groups to return
2384             * @param  end the upper bound of the range of groups to return (not
2385             *         inclusive)
2386             * @return the matching groups ordered by name
2387             */
2388            @Override
2389            public List<Group> search(
2390                    long companyId, long[] classNameIds, String keywords,
2391                    LinkedHashMap<String, Object> params, int start, int end) {
2392    
2393                    return search(
2394                            companyId, classNameIds, GroupConstants.ANY_PARENT_GROUP_ID,
2395                            keywords, params, start, end, null);
2396            }
2397    
2398            /**
2399             * Returns an ordered range of all the groups that match the class name IDs
2400             * and keywords, optionally including the user's inherited organization
2401             * groups and user groups. System and staged groups are not included.
2402             *
2403             * <p>
2404             * Useful when paginating results. Returns a maximum of <code>end -
2405             * start</code> instances. <code>start</code> and <code>end</code> are not
2406             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2407             * refers to the first result in the set. Setting both <code>start</code>
2408             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2409             * result set.
2410             * </p>
2411             *
2412             * @param  companyId the primary key of the company
2413             * @param  classNameIds the primary keys of the class names of the entities
2414             *         the groups are related to (optionally <code>null</code>)
2415             * @param  keywords the keywords (space separated), which may occur in the
2416             *         sites's name, or description (optionally <code>null</code>)
2417             * @param  params the finder params (optionally <code>null</code>). To
2418             *         include a user's organizations, inherited organizations, and user
2419             *         groups in the search, add an entry with key
2420             *         &quot;usersGroups&quot; mapped to the user's ID and an entry with
2421             *         key &quot;inherit&quot; mapped to a non-<code>null</code> object.
2422             *         For more information see {@link
2423             *         com.liferay.portal.service.persistence.GroupFinder}.
2424             * @param  start the lower bound of the range of groups to return
2425             * @param  end the upper bound of the range of groups to return (not
2426             *         inclusive)
2427             * @param  obc the comparator to order the groups (optionally
2428             *         <code>null</code>)
2429             * @return the matching groups ordered by comparator <code>obc</code>
2430             */
2431            @Override
2432            public List<Group> search(
2433                    long companyId, long[] classNameIds, String keywords,
2434                    LinkedHashMap<String, Object> params, int start, int end,
2435                    OrderByComparator<Group> obc) {
2436    
2437                    return search(
2438                            companyId, classNameIds, GroupConstants.ANY_PARENT_GROUP_ID,
2439                            keywords, params, start, end, obc);
2440            }
2441    
2442            /**
2443             * Returns an ordered range of all the groups that match the class name IDs,
2444             * name, and description, optionally including the user's inherited
2445             * organization groups and user groups. System and staged groups are not
2446             * included.
2447             *
2448             * <p>
2449             * Useful when paginating results. Returns a maximum of <code>end -
2450             * start</code> instances. <code>start</code> and <code>end</code> are not
2451             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2452             * refers to the first result in the set. Setting both <code>start</code>
2453             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2454             * result set.
2455             * </p>
2456             *
2457             * @param  companyId the primary key of the company
2458             * @param  classNameIds the primary keys of the class names of the entities
2459             *         the groups are related to (optionally <code>null</code>)
2460             * @param  name the group's name (optionally <code>null</code>)
2461             * @param  description the group's description (optionally
2462             *         <code>null</code>)
2463             * @param  params the finder params (optionally <code>null</code>). To
2464             *         include a user's organizations, inherited organizations, and user
2465             *         groups in the search, add an entry with key
2466             *         &quot;usersGroups&quot; mapped to the user's ID and an entry with
2467             *         key &quot;inherit&quot; mapped to a non-<code>null</code> object.
2468             *         For more information see {@link
2469             *         com.liferay.portal.service.persistence.GroupFinder}.
2470             * @param  andOperator whether every field must match its keywords, or just
2471             *         one field.
2472             * @param  start the lower bound of the range of groups to return
2473             * @param  end the upper bound of the range of groups to return (not
2474             *         inclusive)
2475             * @return the matching groups ordered by name
2476             */
2477            @Override
2478            public List<Group> search(
2479                    long companyId, long[] classNameIds, String name, String description,
2480                    LinkedHashMap<String, Object> params, boolean andOperator, int start,
2481                    int end) {
2482    
2483                    return search(
2484                            companyId, classNameIds, GroupConstants.ANY_PARENT_GROUP_ID, name,
2485                            description, params, andOperator, start, end, null);
2486            }
2487    
2488            /**
2489             * Returns an ordered range of all the groups that match the class name IDs,
2490             * name, and description, optionally including the user's inherited
2491             * organization groups and user groups. System and staged groups are not
2492             * included.
2493             *
2494             * <p>
2495             * Useful when paginating results. Returns a maximum of <code>end -
2496             * start</code> instances. <code>start</code> and <code>end</code> are not
2497             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2498             * refers to the first result in the set. Setting both <code>start</code>
2499             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2500             * result set.
2501             * </p>
2502             *
2503             * @param  companyId the primary key of the company
2504             * @param  classNameIds the primary keys of the class names of the entities
2505             *         the groups are related to (optionally <code>null</code>)
2506             * @param  name the group's name (optionally <code>null</code>)
2507             * @param  description the group's description (optionally
2508             *         <code>null</code>)
2509             * @param  params the finder params (optionally <code>null</code>). To
2510             *         include a user's organizations, inherited organizations, and user
2511             *         groups in the search, add an entry with key
2512             *         &quot;usersGroups&quot; mapped to the user's ID and an entry with
2513             *         key &quot;inherit&quot; mapped to a non-<code>null</code> object.
2514             *         For more information see {@link
2515             *         com.liferay.portal.service.persistence.GroupFinder}.
2516             * @param  andOperator whether every field must match its keywords, or just
2517             *         one field.
2518             * @param  start the lower bound of the range of groups to return
2519             * @param  end the upper bound of the range of groups to return (not
2520             *         inclusive)
2521             * @param  obc the comparator to order the groups (optionally
2522             *         <code>null</code>)
2523             * @return the matching groups ordered by comparator <code>obc</code>
2524             */
2525            @Override
2526            public List<Group> search(
2527                    long companyId, long[] classNameIds, String name, String description,
2528                    LinkedHashMap<String, Object> params, boolean andOperator, int start,
2529                    int end, OrderByComparator<Group> obc) {
2530    
2531                    return search(
2532                            companyId, classNameIds, GroupConstants.ANY_PARENT_GROUP_ID, name,
2533                            description, params, andOperator, start, end, obc);
2534            }
2535    
2536            /**
2537             * Returns an ordered range of all the groups that match the keywords,
2538             * optionally including the user's inherited organization groups and user
2539             * groups. System and staged groups are not included.
2540             *
2541             * <p>
2542             * Useful when paginating results. Returns a maximum of <code>end -
2543             * start</code> instances. <code>start</code> and <code>end</code> are not
2544             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2545             * refers to the first result in the set. Setting both <code>start</code>
2546             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2547             * result set.
2548             * </p>
2549             *
2550             * @param  companyId the primary key of the company
2551             * @param  keywords the keywords (space separated), which may occur in the
2552             *         sites's name, or description (optionally <code>null</code>)
2553             * @param  params the finder params (optionally <code>null</code>). To
2554             *         include the user's inherited organizations and user groups in the
2555             *         search, add entries having &quot;usersGroups&quot; and
2556             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2557             *         information see {@link
2558             *         com.liferay.portal.service.persistence.GroupFinder}.
2559             * @param  start the lower bound of the range of groups to return
2560             * @param  end the upper bound of the range of groups to return (not
2561             *         inclusive)
2562             * @return the matching groups ordered by name
2563             */
2564            @Override
2565            @ThreadLocalCachable
2566            public List<Group> search(
2567                    long companyId, String keywords, LinkedHashMap<String, Object> params,
2568                    int start, int end) {
2569    
2570                    return search(
2571                            companyId, getClassNameIds(), GroupConstants.ANY_PARENT_GROUP_ID,
2572                            keywords, params, start, end, null);
2573            }
2574    
2575            /**
2576             * Returns an ordered range of all the groups that match the keywords,
2577             * optionally including the user's inherited organization groups and user
2578             * groups. System and staged groups are not included.
2579             *
2580             * <p>
2581             * Useful when paginating results. Returns a maximum of <code>end -
2582             * start</code> instances. <code>start</code> and <code>end</code> are not
2583             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2584             * refers to the first result in the set. Setting both <code>start</code>
2585             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2586             * result set.
2587             * </p>
2588             *
2589             * @param  companyId the primary key of the company
2590             * @param  keywords the keywords (space separated), which may occur in the
2591             *         sites's name, or description (optionally <code>null</code>)
2592             * @param  params the finder params (optionally <code>null</code>). To
2593             *         include the user's inherited organizations and user groups in the
2594             *         search, add entries having &quot;usersGroups&quot; and
2595             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2596             *         information see {@link
2597             *         com.liferay.portal.service.persistence.GroupFinder}.
2598             * @param  start the lower bound of the range of groups to return
2599             * @param  end the upper bound of the range of groups to return (not
2600             *         inclusive)
2601             * @param  obc the comparator to order the groups (optionally
2602             *         <code>null</code>)
2603             * @return the matching groups ordered by comparator <code>obc</code>
2604             */
2605            @Override
2606            public List<Group> search(
2607                    long companyId, String keywords, LinkedHashMap<String, Object> params,
2608                    int start, int end, OrderByComparator<Group> obc) {
2609    
2610                    return search(
2611                            companyId, getClassNameIds(), GroupConstants.ANY_PARENT_GROUP_ID,
2612                            keywords, params, start, end, obc);
2613            }
2614    
2615            /**
2616             * Returns an ordered range of all the site groups and organization groups
2617             * that match the name and description, optionally including the user's
2618             * inherited organization groups and user groups. System and staged groups
2619             * are not included.
2620             *
2621             * <p>
2622             * Useful when paginating results. Returns a maximum of <code>end -
2623             * start</code> instances. <code>start</code> and <code>end</code> are not
2624             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2625             * refers to the first result in the set. Setting both <code>start</code>
2626             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2627             * result set.
2628             * </p>
2629             *
2630             * @param  companyId the primary key of the company
2631             * @param  name the group's name (optionally <code>null</code>)
2632             * @param  description the group's description (optionally
2633             *         <code>null</code>)
2634             * @param  params the finder params (optionally <code>null</code>). To
2635             *         include the user's inherited organizations and user groups in the
2636             *         search, add entries having &quot;usersGroups&quot; and
2637             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2638             *         information see {@link
2639             *         com.liferay.portal.service.persistence.GroupFinder}.
2640             * @param  andOperator whether every field must match its keywords, or just
2641             *         one field.
2642             * @param  start the lower bound of the range of groups to return
2643             * @param  end the upper bound of the range of groups to return (not
2644             *         inclusive)
2645             * @return the matching groups ordered by name
2646             */
2647            @Override
2648            public List<Group> search(
2649                    long companyId, String name, String description,
2650                    LinkedHashMap<String, Object> params, boolean andOperator, int start,
2651                    int end) {
2652    
2653                    return search(
2654                            companyId, getClassNameIds(), GroupConstants.ANY_PARENT_GROUP_ID,
2655                            name, description, params, andOperator, start, end, null);
2656            }
2657    
2658            /**
2659             * Returns an ordered range of all the site groups and organization groups
2660             * that match the name and description, optionally including the user's
2661             * inherited organization groups and user groups. System and staged groups
2662             * are not included.
2663             *
2664             * <p>
2665             * Useful when paginating results. Returns a maximum of <code>end -
2666             * start</code> instances. <code>start</code> and <code>end</code> are not
2667             * primary keys, they are indexes in the result set. Thus, <code>0</code>
2668             * refers to the first result in the set. Setting both <code>start</code>
2669             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
2670             * result set.
2671             * </p>
2672             *
2673             * @param  companyId the primary key of the company
2674             * @param  name the group's name (optionally <code>null</code>)
2675             * @param  description the group's description (optionally
2676             *         <code>null</code>)
2677             * @param  params the finder params (optionally <code>null</code>). To
2678             *         include the user's inherited organizations and user groups in the
2679             *         search, add entries having &quot;usersGroups&quot; and
2680             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2681             *         information see {@link
2682             *         com.liferay.portal.service.persistence.GroupFinder}.
2683             * @param  andOperator whether every field must match its keywords, or just
2684             *         one field.
2685             * @param  start the lower bound of the range of groups to return
2686             * @param  end the upper bound of the range of groups to return (not
2687             *         inclusive)
2688             * @param  obc the comparator to order the groups (optionally
2689             *         <code>null</code>)
2690             * @return the matching groups ordered by comparator <code>obc</code>
2691             */
2692            @Override
2693            public List<Group> search(
2694                    long companyId, String name, String description,
2695                    LinkedHashMap<String, Object> params, boolean andOperator, int start,
2696                    int end, OrderByComparator<Group> obc) {
2697    
2698                    return search(
2699                            companyId, getClassNameIds(), GroupConstants.ANY_PARENT_GROUP_ID,
2700                            name, description, params, andOperator, start, end, obc);
2701            }
2702    
2703            /**
2704             * Returns the number of groups belonging to the parent group that match the
2705             * keywords, optionally including the user's inherited organization groups
2706             * and user groups. System and staged groups are not included.
2707             *
2708             * @param  companyId the primary key of the company
2709             * @param  parentGroupId the primary key of the parent group
2710             * @param  keywords the keywords (space separated), which may occur in the
2711             *         sites's name, or description (optionally <code>null</code>)
2712             * @param  params the finder params (optionally <code>null</code>). To
2713             *         include the user's inherited organization groups and user groups
2714             *         in the search, add entries having &quot;usersGroups&quot; and
2715             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2716             *         information see {@link
2717             *         com.liferay.portal.service.persistence.GroupFinder}.
2718             * @return the number of matching groups
2719             */
2720            @Override
2721            @ThreadLocalCachable
2722            public int searchCount(
2723                    long companyId, long parentGroupId, String keywords,
2724                    LinkedHashMap<String, Object> params) {
2725    
2726                    return searchCount(
2727                            companyId, getClassNameIds(), parentGroupId, keywords, params);
2728            }
2729    
2730            /**
2731             * Returns the number of groups belonging to the parent group and immediate
2732             * organization groups that match the name and description, optionally
2733             * including the user's inherited organization groups and user groups.
2734             * System and staged groups are not included.
2735             *
2736             * @param  companyId the primary key of the company
2737             * @param  parentGroupId the primary key of the parent group
2738             * @param  name the group's name (optionally <code>null</code>)
2739             * @param  description the group's description (optionally
2740             *         <code>null</code>)
2741             * @param  params the finder params (optionally <code>null</code>). To
2742             *         include the user's inherited organization groups and user groups
2743             *         in the search, add entries having &quot;usersGroups&quot; and
2744             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2745             *         information see {@link
2746             *         com.liferay.portal.service.persistence.GroupFinder}.
2747             * @param  andOperator whether every field must match its keywords, or just
2748             *         one field.
2749             * @return the number of matching groups
2750             */
2751            @Override
2752            @ThreadLocalCachable
2753            public int searchCount(
2754                    long companyId, long parentGroupId, String name, String description,
2755                    LinkedHashMap<String, Object> params, boolean andOperator) {
2756    
2757                    return searchCount(
2758                            companyId, getClassNameIds(), parentGroupId, name, description,
2759                            params, andOperator);
2760            }
2761    
2762            /**
2763             * Returns the number of groups belonging to the parent group that match the
2764             * class name IDs, and keywords, optionally including the user's inherited
2765             * organization groups and user groups. System and staged groups are not
2766             * included.
2767             *
2768             * @param  companyId the primary key of the company
2769             * @param  classNameIds the primary keys of the class names of the entities
2770             *         the groups are related to (optionally <code>null</code>)
2771             * @param  parentGroupId the primary key of the parent group
2772             * @param  keywords the keywords (space separated), which may occur in the
2773             *         sites's name, or description (optionally <code>null</code>)
2774             * @param  params the finder params (optionally <code>null</code>). To
2775             *         include the user's inherited organization groups and user groups
2776             *         in the search, add entries having &quot;usersGroups&quot; and
2777             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2778             *         information see {@link
2779             *         com.liferay.portal.service.persistence.GroupFinder}.
2780             * @return the number of matching groups
2781             */
2782            @Override
2783            @ThreadLocalCachable
2784            public int searchCount(
2785                    long companyId, long[] classNameIds, long parentGroupId,
2786                    String keywords, LinkedHashMap<String, Object> params) {
2787    
2788                    String[] keywordsArray = getSearchNames(companyId, keywords);
2789    
2790                    boolean andOperator = false;
2791    
2792                    if (Validator.isNull(keywords)) {
2793                            andOperator = true;
2794                    }
2795    
2796                    if (isUseComplexSQL(classNameIds)) {
2797                            return groupFinder.countByC_C_PG_N_D(
2798                                    companyId, classNameIds, parentGroupId, keywordsArray,
2799                                    keywordsArray, params, andOperator);
2800                    }
2801    
2802                    Collection<Group> groups = doSearch(
2803                            companyId, classNameIds, parentGroupId, keywordsArray,
2804                            keywordsArray, params, andOperator);
2805    
2806                    return groups.size();
2807            }
2808    
2809            /**
2810             * Returns the number of groups belonging to the parent group that match the
2811             * class name IDs, name, and description, optionally including the user's
2812             * inherited organization groups and user groups. System and staged groups
2813             * are not included.
2814             *
2815             * @param  companyId the primary key of the company
2816             * @param  classNameIds the primary keys of the class names of the entities
2817             *         the groups are related to (optionally <code>null</code>)
2818             * @param  parentGroupId the primary key of the parent group
2819             * @param  name the group's name (optionally <code>null</code>)
2820             * @param  description the group's description (optionally
2821             *         <code>null</code>)
2822             * @param  params the finder params (optionally <code>null</code>). To
2823             *         include the user's inherited organization groups and user groups
2824             *         in the search, add entries having &quot;usersGroups&quot; and
2825             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2826             *         information see {@link
2827             *         com.liferay.portal.service.persistence.GroupFinder}.
2828             * @param  andOperator whether every field must match its keywords, or just
2829             *         one field.
2830             * @return the number of matching groups
2831             */
2832            @Override
2833            @ThreadLocalCachable
2834            public int searchCount(
2835                    long companyId, long[] classNameIds, long parentGroupId, String name,
2836                    String description, LinkedHashMap<String, Object> params,
2837                    boolean andOperator) {
2838    
2839                    String[] names = getSearchNames(companyId, name);
2840                    String[] descriptions = CustomSQLUtil.keywords(description);
2841    
2842                    if (isUseComplexSQL(classNameIds)) {
2843                            return groupFinder.countByC_C_PG_N_D(
2844                                    companyId, classNameIds, parentGroupId, names, descriptions,
2845                                    params, andOperator);
2846                    }
2847    
2848                    Collection<Group> groups = doSearch(
2849                            companyId, classNameIds, parentGroupId, names, descriptions, params,
2850                            andOperator);
2851    
2852                    return groups.size();
2853            }
2854    
2855            /**
2856             * Returns the number of groups that match the class name IDs, and keywords,
2857             * optionally including the user's inherited organization groups and user
2858             * groups. System and staged groups are not included.
2859             *
2860             * @param  companyId the primary key of the company
2861             * @param  classNameIds the primary keys of the class names of the entities
2862             *         the groups are related to (optionally <code>null</code>)
2863             * @param  keywords the keywords (space separated), which may occur in the
2864             *         sites's name, or description (optionally <code>null</code>)
2865             * @param  params the finder params (optionally <code>null</code>). To
2866             *         include the user's inherited organization groups and user groups
2867             *         in the search, add entries having &quot;usersGroups&quot; and
2868             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2869             *         information see {@link
2870             *         com.liferay.portal.service.persistence.GroupFinder}.
2871             * @return the number of matching groups
2872             */
2873            @Override
2874            @ThreadLocalCachable
2875            public int searchCount(
2876                    long companyId, long[] classNameIds, String keywords,
2877                    LinkedHashMap<String, Object> params) {
2878    
2879                    return searchCount(
2880                            companyId, classNameIds, GroupConstants.ANY_PARENT_GROUP_ID,
2881                            keywords, params);
2882            }
2883    
2884            /**
2885             * Returns the number of groups that match the class name IDs, name, and
2886             * description, optionally including the user's inherited organization
2887             * groups and user groups. System and staged groups are not included.
2888             *
2889             * @param  companyId the primary key of the company
2890             * @param  classNameIds the primary keys of the class names of the entities
2891             *         the groups are related to (optionally <code>null</code>)
2892             * @param  name the group's name (optionally <code>null</code>)
2893             * @param  description the group's description (optionally
2894             *         <code>null</code>)
2895             * @param  params the finder params (optionally <code>null</code>). To
2896             *         include the user's inherited organization groups and user groups
2897             *         in the search, add entries having &quot;usersGroups&quot; and
2898             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2899             *         information see {@link
2900             *         com.liferay.portal.service.persistence.GroupFinder}.
2901             * @param  andOperator whether every field must match its keywords, or just
2902             *         one field.
2903             * @return the number of matching groups
2904             */
2905            @Override
2906            @ThreadLocalCachable
2907            public int searchCount(
2908                    long companyId, long[] classNameIds, String name, String description,
2909                    LinkedHashMap<String, Object> params, boolean andOperator) {
2910    
2911                    return searchCount(
2912                            companyId, classNameIds, GroupConstants.ANY_PARENT_GROUP_ID, name,
2913                            description, params, andOperator);
2914            }
2915    
2916            /**
2917             * Returns the number of groups that match the keywords, optionally
2918             * including the user's inherited organization groups and user groups.
2919             * System and staged groups are not included.
2920             *
2921             * @param  companyId the primary key of the company
2922             * @param  keywords the keywords (space separated), which may occur in the
2923             *         sites's name, or description (optionally <code>null</code>)
2924             * @param  params the finder params (optionally <code>null</code>). To
2925             *         include the user's inherited organization groups and user groups
2926             *         in the search, add entries having &quot;usersGroups&quot; and
2927             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2928             *         information see {@link
2929             *         com.liferay.portal.service.persistence.GroupFinder}.
2930             * @return the number of matching groups
2931             */
2932            @Override
2933            @ThreadLocalCachable
2934            public int searchCount(
2935                    long companyId, String keywords, LinkedHashMap<String, Object> params) {
2936    
2937                    return searchCount(
2938                            companyId, getClassNameIds(), GroupConstants.ANY_PARENT_GROUP_ID,
2939                            keywords, params);
2940            }
2941    
2942            /**
2943             * Returns the number of groups and immediate organization groups that match
2944             * the name and description, optionally including the user's inherited
2945             * organization groups and user groups. System and staged groups are not
2946             * included.
2947             *
2948             * @param  companyId the primary key of the company
2949             * @param  name the group's name (optionally <code>null</code>)
2950             * @param  description the group's description (optionally
2951             *         <code>null</code>)
2952             * @param  params the finder params (optionally <code>null</code>). To
2953             *         include the user's inherited organization groups and user groups
2954             *         in the search, add entries having &quot;usersGroups&quot; and
2955             *         &quot;inherit&quot; as keys mapped to the the user's ID. For more
2956             *         information see {@link
2957             *         com.liferay.portal.service.persistence.GroupFinder}.
2958             * @param  andOperator whether every field must match its keywords, or just
2959             *         one field.
2960             * @return the number of matching groups
2961             */
2962            @Override
2963            @ThreadLocalCachable
2964            public int searchCount(
2965                    long companyId, String name, String description,
2966                    LinkedHashMap<String, Object> params, boolean andOperator) {
2967    
2968                    return searchCount(
2969                            companyId, getClassNameIds(), GroupConstants.ANY_PARENT_GROUP_ID,
2970                            name, description, params, andOperator);
2971            }
2972    
2973            /**
2974             * Sets the groups associated with the role, removing and adding
2975             * associations as necessary.
2976             *
2977             * @param roleId the primary key of the role
2978             * @param groupIds the primary keys of the groups
2979             */
2980            @Override
2981            public void setRoleGroups(long roleId, long[] groupIds) {
2982                    rolePersistence.setGroups(roleId, groupIds);
2983    
2984                    PermissionCacheUtil.clearCache();
2985            }
2986    
2987            /**
2988             * Removes the groups from the role.
2989             *
2990             * @param roleId the primary key of the role
2991             * @param groupIds the primary keys of the groups
2992             */
2993            @Override
2994            public void unsetRoleGroups(long roleId, long[] groupIds) {
2995                    rolePersistence.removeGroups(roleId, groupIds);
2996    
2997                    PermissionCacheUtil.clearCache();
2998            }
2999    
3000            /**
3001             * Removes the user from the groups.
3002             *
3003             * @param userId the primary key of the user
3004             * @param groupIds the primary keys of the groups
3005             */
3006            @Override
3007            public void unsetUserGroups(long userId, long[] groupIds) {
3008                    userGroupRoleLocalService.deleteUserGroupRoles(userId, groupIds);
3009    
3010                    userPersistence.removeGroups(userId, groupIds);
3011    
3012                    PermissionCacheUtil.clearCache(userId);
3013            }
3014    
3015            /**
3016             * Updates the group's asset replacing categories and tag names.
3017             *
3018             * @param  userId the primary key of the user
3019             * @param  group the group
3020             * @param  assetCategoryIds the primary keys of the asset categories
3021             *         (optionally <code>null</code>)
3022             * @param  assetTagNames the asset tag names (optionally <code>null</code>)
3023             * @throws PortalException if a portal exception occurred
3024             */
3025            @Override
3026            public void updateAsset(
3027                            long userId, Group group, long[] assetCategoryIds,
3028                            String[] assetTagNames)
3029                    throws PortalException {
3030    
3031                    User user = userPersistence.findByPrimaryKey(userId);
3032    
3033                    Company company = companyPersistence.findByPrimaryKey(
3034                            user.getCompanyId());
3035    
3036                    Group companyGroup = company.getGroup();
3037    
3038                    assetEntryLocalService.updateEntry(
3039                            userId, companyGroup.getGroupId(), null, null,
3040                            Group.class.getName(), group.getGroupId(), null, 0,
3041                            assetCategoryIds, assetTagNames, false, null, null, null, null,
3042                            group.getDescriptiveName(), group.getDescription(), null, null,
3043                            null, 0, 0, null);
3044            }
3045    
3046            /**
3047             * Updates the group's friendly URL.
3048             *
3049             * @param  groupId the primary key of the group
3050             * @param  friendlyURL the group's new friendlyURL (optionally
3051             *         <code>null</code>)
3052             * @return the group
3053             * @throws PortalException if a portal exception occurred
3054             */
3055            @Override
3056            public Group updateFriendlyURL(long groupId, String friendlyURL)
3057                    throws PortalException {
3058    
3059                    Group group = groupPersistence.findByPrimaryKey(groupId);
3060    
3061                    if (group.isUser()) {
3062                            User user = userPersistence.findByPrimaryKey(group.getClassPK());
3063    
3064                            friendlyURL = StringPool.SLASH + user.getScreenName();
3065    
3066                            if (group.getFriendlyURL().equals(friendlyURL)) {
3067                                    return group;
3068                            }
3069                    }
3070    
3071                    friendlyURL = getFriendlyURL(
3072                            group.getCompanyId(), groupId, group.getClassNameId(),
3073                            group.getClassPK(), StringPool.BLANK, friendlyURL);
3074    
3075                    validateFriendlyURL(
3076                            group.getCompanyId(), group.getGroupId(), group.getClassNameId(),
3077                            group.getClassPK(), friendlyURL);
3078    
3079                    group.setFriendlyURL(friendlyURL);
3080    
3081                    groupPersistence.update(group);
3082    
3083                    return group;
3084            }
3085    
3086            @Override
3087            public Group updateGroup(
3088                            long groupId, long parentGroupId, Map<Locale, String> nameMap,
3089                            Map<Locale, String> descriptionMap, int type,
3090                            boolean manualMembership, int membershipRestriction,
3091                            String friendlyURL, boolean inheritContent, boolean active,
3092                            ServiceContext serviceContext)
3093                    throws PortalException {
3094    
3095                    Group group = groupPersistence.findByPrimaryKey(groupId);
3096    
3097                    String className = group.getClassName();
3098                    long classNameId = group.getClassNameId();
3099                    long classPK = group.getClassPK();
3100    
3101                    String groupKey = group.getGroupKey();
3102    
3103                    if ((nameMap != null) &&
3104                            Validator.isNotNull(nameMap.get(LocaleUtil.getDefault()))) {
3105    
3106                            groupKey = nameMap.get(LocaleUtil.getDefault());
3107                    }
3108    
3109                    friendlyURL = getFriendlyURL(
3110                            group.getCompanyId(), groupId, classNameId, classPK,
3111                            StringPool.BLANK, friendlyURL);
3112    
3113                    if ((classNameId <= 0) || className.equals(Group.class.getName())) {
3114                            validateGroupKey(
3115                                    group.getGroupId(), group.getCompanyId(), groupKey,
3116                                    group.isSite());
3117                    }
3118                    else if (className.equals(Organization.class.getName())) {
3119                            Organization organization =
3120                                    organizationPersistence.findByPrimaryKey(classPK);
3121    
3122                            groupKey = getOrgGroupName(organization.getName());
3123                    }
3124                    else if (!GroupConstants.USER_PERSONAL_SITE.equals(
3125                                            group.getGroupKey())) {
3126    
3127                            groupKey = String.valueOf(classPK);
3128                    }
3129    
3130                    if (PortalUtil.isSystemGroup(group.getGroupKey()) &&
3131                            !groupKey.equals(group.getGroupKey())) {
3132    
3133                            throw new RequiredGroupException.MustNotDeleteSystemGroup(
3134                                    group.getGroupId());
3135                    }
3136    
3137                    validateFriendlyURL(
3138                            group.getCompanyId(), group.getGroupId(), group.getClassNameId(),
3139                            group.getClassPK(), friendlyURL);
3140    
3141                    validateParentGroup(group.getGroupId(), parentGroupId);
3142    
3143                    group.setParentGroupId(parentGroupId);
3144                    group.setTreePath(group.buildTreePath());
3145                    group.setGroupKey(groupKey);
3146                    group.setNameMap(nameMap);
3147                    group.setDescriptionMap(descriptionMap);
3148                    group.setType(type);
3149                    group.setManualMembership(manualMembership);
3150                    group.setMembershipRestriction(membershipRestriction);
3151                    group.setFriendlyURL(friendlyURL);
3152                    group.setInheritContent(inheritContent);
3153                    group.setActive(active);
3154    
3155                    if ((serviceContext != null) && group.isSite()) {
3156                            group.setExpandoBridgeAttributes(serviceContext);
3157                    }
3158    
3159                    groupPersistence.update(group);
3160    
3161                    // Asset
3162    
3163                    if ((serviceContext == null) || !group.isSite()) {
3164                            return group;
3165                    }
3166    
3167                    User user = null;
3168    
3169                    user = userPersistence.fetchByPrimaryKey(group.getCreatorUserId());
3170    
3171                    if (user == null) {
3172                            user = userPersistence.fetchByPrimaryKey(
3173                                    serviceContext.getUserId());
3174                    }
3175    
3176                    if (user == null) {
3177                            user = userLocalService.getDefaultUser(group.getCompanyId());
3178                    }
3179    
3180                    updateAsset(
3181                            user.getUserId(), group, serviceContext.getAssetCategoryIds(),
3182                            serviceContext.getAssetTagNames());
3183    
3184                    return group;
3185            }
3186    
3187            /**
3188             * Updates the group.
3189             *
3190             * @param      groupId the primary key of the group
3191             * @param      parentGroupId the primary key of the parent group
3192             * @param      name the name's key
3193             * @param      description the group's new description (optionally
3194             *             <code>null</code>)
3195             * @param      type the group's new type. For more information see {@link
3196             *             GroupConstants}.
3197             * @param      manualMembership whether manual membership is allowed for the
3198             *             group
3199             * @param      membershipRestriction the group's membership restriction. For
3200             *             more information see {@link GroupConstants}.
3201             * @param      friendlyURL the group's new friendlyURL (optionally
3202             *             <code>null</code>)
3203             * @param      inheritContent whether to inherit content from the parent
3204             *             group
3205             * @param      active whether the group is active
3206             * @param      serviceContext the service context to be applied (optionally
3207             *             <code>null</code>). Can set asset category IDs and asset tag
3208             *             names for the group.
3209             * @return     the group
3210             * @throws     PortalException if a portal exception occurred
3211             * @deprecated As of 7.0.0, replaced by {@link #updateGroup(long, long, Map,
3212             *             Map, int, boolean, int, String, boolean, boolean,
3213             *             ServiceContext)}
3214             */
3215            @Deprecated
3216            @Override
3217            public Group updateGroup(
3218                            long groupId, long parentGroupId, String name, String description,
3219                            int type, boolean manualMembership, int membershipRestriction,
3220                            String friendlyURL, boolean inheritContent, boolean active,
3221                            ServiceContext serviceContext)
3222                    throws PortalException {
3223    
3224                    return updateGroup(
3225                            groupId, parentGroupId, getLocalizationMap(name),
3226                            getLocalizationMap(description), type, manualMembership,
3227                            membershipRestriction, friendlyURL, inheritContent, active,
3228                            serviceContext);
3229            }
3230    
3231            /**
3232             * Updates the group's type settings.
3233             *
3234             * @param  groupId the primary key of the group
3235             * @param  typeSettings the group's new type settings (optionally
3236             *         <code>null</code>)
3237             * @return the group
3238             * @throws PortalException if a portal exception occurred
3239             */
3240            @Override
3241            public Group updateGroup(long groupId, String typeSettings)
3242                    throws PortalException {
3243    
3244                    Group group = groupPersistence.findByPrimaryKey(groupId);
3245    
3246                    UnicodeProperties oldTypeSettingsProperties =
3247                            group.getTypeSettingsProperties();
3248    
3249                    UnicodeProperties typeSettingsProperties = new UnicodeProperties(true);
3250    
3251                    typeSettingsProperties.fastLoad(typeSettings);
3252    
3253                    String newLanguageIds = typeSettingsProperties.getProperty(
3254                            PropsKeys.LOCALES);
3255    
3256                    if (Validator.isNotNull(newLanguageIds)) {
3257                            String oldLanguageIds = oldTypeSettingsProperties.getProperty(
3258                                    PropsKeys.LOCALES, StringPool.BLANK);
3259    
3260                            String defaultLanguageId = typeSettingsProperties.getProperty(
3261                                    "languageId", LocaleUtil.toLanguageId(LocaleUtil.getDefault()));
3262    
3263                            validateLanguageIds(defaultLanguageId, newLanguageIds);
3264    
3265                            if (!Validator.equals(oldLanguageIds, newLanguageIds)) {
3266                                    LanguageUtil.resetAvailableGroupLocales(groupId);
3267                            }
3268                    }
3269    
3270                    group.setTypeSettings(typeSettings);
3271    
3272                    groupPersistence.update(group);
3273    
3274                    return group;
3275            }
3276    
3277            /**
3278             * Associates the group with a main site if the group is an organization.
3279             *
3280             * @param  groupId the primary key of the group
3281             * @param  site whether the group is to be associated with a main site
3282             * @return the group
3283             * @throws PortalException if a portal exception occurred
3284             */
3285            @Override
3286            public Group updateSite(long groupId, boolean site) throws PortalException {
3287                    Group group = groupPersistence.findByPrimaryKey(groupId);
3288    
3289                    if (!group.isOrganization()) {
3290                            return group;
3291                    }
3292    
3293                    group.setSite(site);
3294    
3295                    groupPersistence.update(group);
3296    
3297                    return group;
3298            }
3299    
3300            protected void addControlPanelLayouts(Group group) throws PortalException {
3301                    long defaultUserId = userLocalService.getDefaultUserId(
3302                            group.getCompanyId());
3303    
3304                    String friendlyURL = getFriendlyURL(
3305                            PropsValues.CONTROL_PANEL_LAYOUT_FRIENDLY_URL);
3306    
3307                    ServiceContext serviceContext = new ServiceContext();
3308    
3309                    serviceContext.setAttribute(
3310                            "layout.instanceable.allowed", Boolean.TRUE);
3311    
3312                    layoutLocalService.addLayout(
3313                            defaultUserId, group.getGroupId(), true,
3314                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID,
3315                            PropsValues.CONTROL_PANEL_LAYOUT_NAME, StringPool.BLANK,
3316                            StringPool.BLANK, LayoutConstants.TYPE_CONTROL_PANEL, false,
3317                            friendlyURL, serviceContext);
3318            }
3319    
3320            protected void addDefaultGuestPublicLayoutByProperties(Group group)
3321                    throws PortalException {
3322    
3323                    List<Portlet> portlets = portletLocalService.getPortlets(
3324                            group.getCompanyId());
3325    
3326                    if (portlets.isEmpty()) {
3327    
3328                            // LPS-38457
3329    
3330                            return;
3331                    }
3332    
3333                    long defaultUserId = userLocalService.getDefaultUserId(
3334                            group.getCompanyId());
3335                    String friendlyURL = getFriendlyURL(
3336                            PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_FRIENDLY_URL);
3337    
3338                    ServiceContext serviceContext = new ServiceContext();
3339    
3340                    Layout layout = layoutLocalService.addLayout(
3341                            defaultUserId, group.getGroupId(), false,
3342                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID,
3343                            PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_NAME, StringPool.BLANK,
3344                            StringPool.BLANK, LayoutConstants.TYPE_PORTLET, false, friendlyURL,
3345                            serviceContext);
3346    
3347                    LayoutTypePortlet layoutTypePortlet =
3348                            (LayoutTypePortlet)layout.getLayoutType();
3349    
3350                    layoutTypePortlet.setLayoutTemplateId(
3351                            0, PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_TEMPLATE_ID, false);
3352    
3353                    LayoutTemplate layoutTemplate = layoutTypePortlet.getLayoutTemplate();
3354    
3355                    for (String columnId : layoutTemplate.getColumns()) {
3356                            String keyPrefix = PropsKeys.DEFAULT_GUEST_PUBLIC_LAYOUT_PREFIX;
3357    
3358                            String portletIds = PropsUtil.get(keyPrefix.concat(columnId));
3359    
3360                            layoutTypePortlet.addPortletIds(
3361                                    0, StringUtil.split(portletIds), columnId, false);
3362                    }
3363    
3364                    layoutLocalService.updateLayout(
3365                            layout.getGroupId(), layout.isPrivateLayout(), layout.getLayoutId(),
3366                            layout.getTypeSettings());
3367    
3368                    boolean updateLayoutSet = false;
3369    
3370                    LayoutSet layoutSet = layout.getLayoutSet();
3371    
3372                    if (Validator.isNotNull(
3373                                    PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_REGULAR_THEME_ID)) {
3374    
3375                            layoutSet.setThemeId(
3376                                    PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_REGULAR_THEME_ID);
3377    
3378                            updateLayoutSet = true;
3379                    }
3380    
3381                    if (Validator.isNotNull(
3382                                    PropsValues.
3383                                            DEFAULT_GUEST_PUBLIC_LAYOUT_REGULAR_COLOR_SCHEME_ID)) {
3384    
3385                            layoutSet.setColorSchemeId(
3386                                    PropsValues.
3387                                            DEFAULT_GUEST_PUBLIC_LAYOUT_REGULAR_COLOR_SCHEME_ID);
3388    
3389                            updateLayoutSet = true;
3390                    }
3391    
3392                    if (Validator.isNotNull(
3393                                    PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_WAP_THEME_ID)) {
3394    
3395                            layoutSet.setWapThemeId(
3396                                    PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_WAP_THEME_ID);
3397    
3398                            updateLayoutSet = true;
3399                    }
3400    
3401                    if (Validator.isNotNull(
3402                                    PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_WAP_COLOR_SCHEME_ID)) {
3403    
3404                            layoutSet.setWapColorSchemeId(
3405                                    PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_WAP_COLOR_SCHEME_ID);
3406    
3407                            updateLayoutSet = true;
3408                    }
3409    
3410                    if (updateLayoutSet) {
3411                            layoutSetLocalService.updateLayoutSet(layoutSet);
3412                    }
3413            }
3414    
3415            protected void addDefaultGuestPublicLayouts(Group group)
3416                    throws PortalException {
3417    
3418                    if (publicLARFile != null) {
3419                            addDefaultGuestPublicLayoutsByLAR(group, publicLARFile);
3420                    }
3421                    else {
3422                            addDefaultGuestPublicLayoutByProperties(group);
3423                    }
3424            }
3425    
3426            protected void addDefaultGuestPublicLayoutsByLAR(Group group, File larFile)
3427                    throws PortalException {
3428    
3429                    User defaultUser = userLocalService.getDefaultUser(
3430                            group.getCompanyId());
3431    
3432                    Map<String, String[]> parameterMap = new HashMap<>();
3433    
3434                    parameterMap.put(
3435                            PortletDataHandlerKeys.PERMISSIONS,
3436                            new String[] {Boolean.TRUE.toString()});
3437                    parameterMap.put(
3438                            PortletDataHandlerKeys.PORTLET_CONFIGURATION,
3439                            new String[] {Boolean.TRUE.toString()});
3440                    parameterMap.put(
3441                            PortletDataHandlerKeys.PORTLET_DATA,
3442                            new String[] {Boolean.TRUE.toString()});
3443                    parameterMap.put(
3444                            PortletDataHandlerKeys.PORTLET_DATA_CONTROL_DEFAULT,
3445                            new String[] {Boolean.TRUE.toString()});
3446    
3447                    Map<String, Serializable> importLayoutSettingsMap =
3448                            ExportImportConfigurationSettingsMapFactory.
3449                                    buildImportLayoutSettingsMap(
3450                                            defaultUser, group.getGroupId(), false, null, parameterMap);
3451    
3452                    ExportImportConfiguration exportImportConfiguration =
3453                            exportImportConfigurationLocalService.
3454                                    addDraftExportImportConfiguration(
3455                                            defaultUser.getUserId(),
3456                                            ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT,
3457                                            importLayoutSettingsMap);
3458    
3459                    exportImportLocalService.importLayouts(
3460                            exportImportConfiguration, larFile);
3461            }
3462    
3463            protected void addPortletDefaultData(Group group) throws PortalException {
3464                    PortletDataContext portletDataContext =
3465                            PortletDataContextFactoryUtil.createPreparePortletDataContext(
3466                                    group.getCompanyId(), group.getGroupId(), null, null);
3467    
3468                    List<PortletDataHandler> portletDataHandlers = getPortletDataHandlers(
3469                            group);
3470    
3471                    for (PortletDataHandler portletDataHandler : portletDataHandlers) {
3472                            try {
3473                                    portletDataHandler.addDefaultData(
3474                                            portletDataContext, portletDataHandler.getPortletId(),
3475                                            null);
3476                            }
3477                            catch (Exception e) {
3478                                    _log.error(
3479                                            "Unable to add default data for portlet " +
3480                                                    portletDataHandler.getPortletId() + " in group " +
3481                                                            group.getGroupId());
3482    
3483                                    if (portletDataHandler.isRollbackOnException()) {
3484                                            throw new SystemException(e);
3485                                    }
3486                            }
3487                    }
3488            }
3489    
3490            protected void deletePortletData(Group group) throws PortalException {
3491                    PortletDataContext portletDataContext =
3492                            PortletDataContextFactoryUtil.createPreparePortletDataContext(
3493                                    group.getCompanyId(), group.getGroupId(), null, null);
3494    
3495                    List<PortletDataHandler> portletDataHandlers = getPortletDataHandlers(
3496                            group);
3497    
3498                    for (PortletDataHandler portletDataHandler : portletDataHandlers) {
3499                            try {
3500                                    portletDataHandler.deleteData(
3501                                            portletDataContext, portletDataHandler.getPortletId(),
3502                                            null);
3503                            }
3504                            catch (Exception e) {
3505                                    _log.error(
3506                                            "Unable to delete data for portlet " +
3507                                                    portletDataHandler.getPortletId() + " in group " +
3508                                                            group.getGroupId());
3509    
3510                                    if (portletDataHandler.isRollbackOnException()) {
3511                                            throw new SystemException(e);
3512                                    }
3513                            }
3514                    }
3515            }
3516    
3517            protected Collection<Group> doSearch(
3518                    long companyId, long[] classNameIds, long parentGroupId, String[] names,
3519                    String[] descriptions, LinkedHashMap<String, Object> params,
3520                    boolean andOperator) {
3521    
3522                    boolean parentGroupIdEquals = true;
3523    
3524                    if (parentGroupId == GroupConstants.ANY_PARENT_GROUP_ID) {
3525                            parentGroupIdEquals = false;
3526                    }
3527    
3528                    params = new LinkedHashMap<>(params);
3529    
3530                    Boolean active = (Boolean)params.remove("active");
3531                    List<Long> excludedGroupIds = (List<Long>)params.remove(
3532                            "excludedGroupIds");
3533                    List<Group> groupsTree = (List<Group>)params.remove("groupsTree");
3534                    Boolean manualMembership = (Boolean)params.remove("manualMembership");
3535                    Integer membershipRestriction = (Integer)params.remove(
3536                            "membershipRestriction");
3537                    Boolean site = (Boolean)params.remove("site");
3538                    List<Integer> types = (List<Integer>)params.remove("types");
3539    
3540                    Collection<Group> groups = new HashSet<>();
3541    
3542                    Long userId = (Long)params.remove("usersGroups");
3543    
3544                    for (long classNameId : classNameIds) {
3545                            groups.addAll(groupPersistence.findByC_C(companyId, classNameId));
3546                    }
3547    
3548                    Iterator<Group> iterator = groups.iterator();
3549    
3550                    while (iterator.hasNext()) {
3551                            Group group = iterator.next();
3552    
3553                            // Filter by live group ID
3554    
3555                            long liveGroupId = group.getLiveGroupId();
3556    
3557                            if (liveGroupId != 0) {
3558                                    iterator.remove();
3559    
3560                                    continue;
3561                            }
3562    
3563                            // Filter by parent group ID
3564    
3565                            long groupParentGroupId = group.getParentGroupId();
3566    
3567                            if ((parentGroupIdEquals &&
3568                                     (groupParentGroupId != parentGroupId)) ||
3569                                    (!parentGroupIdEquals &&
3570                                     (groupParentGroupId == parentGroupId))) {
3571    
3572                                    iterator.remove();
3573    
3574                                    continue;
3575                            }
3576    
3577                            // Filter by name and description
3578    
3579                            String groupKey = group.getGroupKey();
3580    
3581                            if (groupKey.equals(GroupConstants.CONTROL_PANEL)) {
3582                                    iterator.remove();
3583    
3584                                    continue;
3585                            }
3586    
3587                            boolean containsName = matches(group.getNameCurrentValue(), names);
3588                            boolean containsDescription = matches(
3589                                    group.getDescriptionCurrentValue(), descriptions);
3590    
3591                            if ((andOperator && (!containsName || !containsDescription)) ||
3592                                    (!andOperator && !containsName && !containsDescription)) {
3593    
3594                                    iterator.remove();
3595    
3596                                    continue;
3597                            }
3598    
3599                            // Filter by active
3600    
3601                            if (active != null) {
3602                                    if (active != group.isActive()) {
3603                                            iterator.remove();
3604    
3605                                            continue;
3606                                    }
3607                            }
3608    
3609                            // Filter by excluded group IDs
3610    
3611                            if ((excludedGroupIds != null) &&
3612                                    excludedGroupIds.contains(group.getGroupId())) {
3613    
3614                                    iterator.remove();
3615    
3616                                    continue;
3617                            }
3618    
3619                            // Filter by groups tree
3620    
3621                            if (groupsTree != null) {
3622                                    String treePath = group.getTreePath();
3623    
3624                                    boolean matched = false;
3625    
3626                                    for (Group groupTree : groupsTree) {
3627                                            String groupTreePath = StringUtil.quote(
3628                                                    String.valueOf(groupTree.getGroupId()),
3629                                                    StringPool.SLASH);
3630    
3631                                            if (treePath.contains(groupTreePath)) {
3632                                                    matched = true;
3633    
3634                                                    break;
3635                                            }
3636                                    }
3637    
3638                                    if (!matched) {
3639                                            iterator.remove();
3640    
3641                                            continue;
3642                                    }
3643                            }
3644    
3645                            // Filter by manual membership
3646    
3647                            if ((manualMembership != null) &&
3648                                    (manualMembership != group.isManualMembership())) {
3649    
3650                                    iterator.remove();
3651    
3652                                    continue;
3653                            }
3654    
3655                            // Filter by membership restriction
3656    
3657                            if ((membershipRestriction != null) &&
3658                                    (membershipRestriction != group.getMembershipRestriction())) {
3659    
3660                                    iterator.remove();
3661    
3662                                    continue;
3663                            }
3664    
3665                            // Filter by site
3666    
3667                            if (site != null) {
3668                                    if (site != group.isSite()) {
3669                                            iterator.remove();
3670    
3671                                            continue;
3672                                    }
3673                            }
3674    
3675                            // Filter by type and types
3676    
3677                            int type = group.getType();
3678    
3679                            if (type == 4) {
3680                                    iterator.remove();
3681    
3682                                    continue;
3683                            }
3684    
3685                            if ((types != null) && !types.contains(type)) {
3686                                    iterator.remove();
3687    
3688                                    continue;
3689                            }
3690                    }
3691    
3692                    // Join by role permissions
3693    
3694                    RolePermissions rolePermissions = (RolePermissions)params.remove(
3695                            "rolePermissions");
3696    
3697                    if (rolePermissions != null) {
3698                            ResourceAction resourceAction =
3699                                    resourceActionLocalService.fetchResourceAction(
3700                                            rolePermissions.getName(), rolePermissions.getActionId());
3701    
3702                            if (resourceAction != null) {
3703                                    Set<Group> rolePermissionsGroups = new HashSet<>();
3704    
3705                                    if (resourceBlockLocalService.isSupported(
3706                                                    rolePermissions.getName())) {
3707    
3708                                            List<ResourceTypePermission> resourceTypePermissions =
3709                                                    resourceTypePermissionPersistence.findByRoleId(
3710                                                            rolePermissions.getRoleId());
3711    
3712                                            for (ResourceTypePermission resourceTypePermission :
3713                                                            resourceTypePermissions) {
3714    
3715                                                    if ((resourceTypePermission.getCompanyId() ==
3716                                                                    companyId) &&
3717                                                            Validator.equals(
3718                                                                    rolePermissions.getName(),
3719                                                                    resourceTypePermission.getName()) &&
3720                                                            resourceTypePermission.hasAction(resourceAction)) {
3721    
3722                                                            Group group = groupPersistence.fetchByPrimaryKey(
3723                                                                    resourceTypePermission.getGroupId());
3724    
3725                                                            if (group != null) {
3726                                                                    rolePermissionsGroups.add(group);
3727                                                            }
3728                                                    }
3729                                            }
3730                                    }
3731                                    else {
3732                                            List<ResourcePermission> resourcePermissions =
3733                                                    resourcePermissionPersistence.findByC_N_S(
3734                                                            companyId, rolePermissions.getName(),
3735                                                            rolePermissions.getScope());
3736    
3737                                            for (ResourcePermission resourcePermission :
3738                                                            resourcePermissions) {
3739    
3740                                                    if ((resourcePermission.getRoleId() ==
3741                                                                    rolePermissions.getRoleId()) &&
3742                                                            resourcePermission.hasAction(
3743                                                                    resourceAction)) {
3744    
3745                                                            Group group = groupPersistence.fetchByPrimaryKey(
3746                                                                    GetterUtil.getLong(
3747                                                                            resourcePermission.getPrimKey()));
3748    
3749                                                            if (group != null) {
3750                                                                    rolePermissionsGroups.add(group);
3751                                                            }
3752                                                    }
3753                                            }
3754                                    }
3755    
3756                                    groups.retainAll(rolePermissionsGroups);
3757                            }
3758                    }
3759    
3760                    // Join by Groups_Roles
3761    
3762                    Long roleId = (Long)params.remove("groupsRoles");
3763    
3764                    if (roleId != null) {
3765                            groups.retainAll(rolePersistence.getGroups(roleId));
3766                    }
3767    
3768                    if (userId == null) {
3769                            return groups;
3770                    }
3771    
3772                    // Join by Users_Groups
3773    
3774                    Set<Group> joinedGroups = new HashSet<>(
3775                            userPersistence.getGroups(userId));
3776    
3777                    boolean inherit = GetterUtil.getBoolean(params.remove("inherit"), true);
3778    
3779                    if (inherit) {
3780    
3781                            // Join by Users_Orgs
3782    
3783                            long[] organizationIds = userPersistence.getOrganizationPrimaryKeys(
3784                                    userId);
3785    
3786                            for (long organizationId : organizationIds) {
3787                                    for (Group group : groups) {
3788                                            if (organizationId == group.getClassPK()) {
3789                                                    joinedGroups.add(group);
3790                                            }
3791                                    }
3792                            }
3793    
3794                            // Join by Groups_Orgs and Users_Orgs
3795    
3796                            for (long organizationId : organizationIds) {
3797                                    joinedGroups.addAll(
3798                                            organizationPersistence.getGroups(organizationId));
3799                            }
3800    
3801                            // Join by Groups_UserGroups and Users_UserGroups
3802    
3803                            long[] userGroupIds = userPersistence.getUserGroupPrimaryKeys(
3804                                    userId);
3805    
3806                            for (long userGroupId : userGroupIds) {
3807                                    joinedGroups.addAll(
3808                                            userGroupPersistence.getGroups(userGroupId));
3809                            }
3810                    }
3811    
3812                    if (_log.isDebugEnabled() && !params.isEmpty()) {
3813                            _log.debug("Unprocessed parameters " + MapUtil.toString(params));
3814                    }
3815    
3816                    if (joinedGroups.size() > groups.size()) {
3817                            groups.retainAll(joinedGroups);
3818    
3819                            return groups;
3820                    }
3821                    else {
3822                            joinedGroups.retainAll(groups);
3823    
3824                            return joinedGroups;
3825                    }
3826            }
3827    
3828            protected long[] getClassNameIds() {
3829                    if (_classNameIds == null) {
3830                            _classNameIds = new long[] {
3831                                    classNameLocalService.getClassNameId(Group.class),
3832                                    classNameLocalService.getClassNameId(Organization.class)
3833                            };
3834                    }
3835    
3836                    return _classNameIds;
3837            }
3838    
3839            protected String getFriendlyURL(
3840                            long companyId, long groupId, long classNameId, long classPK,
3841                            String friendlyName, String friendlyURL)
3842                    throws PortalException {
3843    
3844                    friendlyURL = getFriendlyURL(friendlyURL);
3845    
3846                    if (Validator.isNotNull(friendlyURL)) {
3847                            return friendlyURL;
3848                    }
3849    
3850                    friendlyURL = StringPool.SLASH + getFriendlyURL(friendlyName);
3851    
3852                    String originalFriendlyURL = friendlyURL;
3853    
3854                    for (int i = 1;; i++) {
3855                            try {
3856                                    validateFriendlyURL(
3857                                            companyId, groupId, classNameId, classPK, friendlyURL);
3858    
3859                                    break;
3860                            }
3861                            catch (GroupFriendlyURLException gfurle) {
3862                                    int type = gfurle.getType();
3863    
3864                                    if (type == GroupFriendlyURLException.DUPLICATE) {
3865                                            friendlyURL = originalFriendlyURL + i;
3866                                    }
3867                                    else {
3868                                            friendlyURL = StringPool.SLASH + classPK;
3869    
3870                                            break;
3871                                    }
3872                            }
3873                    }
3874    
3875                    return friendlyURL;
3876            }
3877    
3878            protected String getFriendlyURL(String friendlyURL) {
3879                    return FriendlyURLNormalizerUtil.normalize(friendlyURL);
3880            }
3881    
3882            protected String getOrgGroupName(String name) {
3883                    return name + ORGANIZATION_NAME_SUFFIX;
3884            }
3885    
3886            protected List<PortletDataHandler> getPortletDataHandlers(Group group) {
3887                    List<Portlet> portlets = portletLocalService.getPortlets(
3888                            group.getCompanyId());
3889    
3890                    List<PortletDataHandler> portletDataHandlers = new ArrayList<>(
3891                            portlets.size());
3892    
3893                    for (Portlet portlet : portlets) {
3894                            if (!portlet.isActive()) {
3895                                    continue;
3896                            }
3897    
3898                            PortletDataHandler portletDataHandler =
3899                                    portlet.getPortletDataHandlerInstance();
3900    
3901                            if ((portletDataHandler != null) &&
3902                                    !portletDataHandler.isDataPortalLevel()) {
3903    
3904                                    portletDataHandlers.add(portletDataHandler);
3905                            }
3906                    }
3907    
3908                    return portletDataHandlers;
3909            }
3910    
3911            protected String[] getSearchNames(long companyId, String name) {
3912                    if (Validator.isNull(name)) {
3913                            return new String[] {null};
3914                    }
3915    
3916                    Company company = companyPersistence.fetchByPrimaryKey(companyId);
3917    
3918                    if (company == null) {
3919                            return CustomSQLUtil.keywords(name);
3920                    }
3921    
3922                    Account account = accountPersistence.fetchByPrimaryKey(
3923                            company.getAccountId());
3924    
3925                    if (account == null) {
3926                            return CustomSQLUtil.keywords(name);
3927                    }
3928    
3929                    String companyName = account.getName();
3930    
3931                    if (StringUtil.wildcardMatches(
3932                                    companyName, name, CharPool.UNDERLINE, CharPool.PERCENT,
3933                                    CharPool.BACK_SLASH, false)) {
3934    
3935                            String[] searchNames = CustomSQLUtil.keywords(name);
3936    
3937                            String guestName = StringUtil.quote(
3938                                    StringUtil.toLowerCase(GroupConstants.GUEST),
3939                                    StringPool.PERCENT);
3940    
3941                            return ArrayUtil.append(searchNames, guestName);
3942                    }
3943    
3944                    return CustomSQLUtil.keywords(name);
3945            }
3946    
3947            protected void initImportLARFile() {
3948                    String publicLARFileName = PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUTS_LAR;
3949    
3950                    if (_log.isDebugEnabled()) {
3951                            _log.debug("Reading public LAR file " + publicLARFileName);
3952                    }
3953    
3954                    if (Validator.isNotNull(publicLARFileName)) {
3955                            publicLARFile = new File(publicLARFileName);
3956    
3957                            if (!publicLARFile.exists()) {
3958                                    _log.error(
3959                                            "Public LAR file " + publicLARFile + " does not exist");
3960    
3961                                    publicLARFile = null;
3962                            }
3963                            else {
3964                                    if (_log.isDebugEnabled()) {
3965                                            _log.debug("Using public LAR file " + publicLARFileName);
3966                                    }
3967                            }
3968                    }
3969            }
3970    
3971            protected void initUserPersonalSitePermissions(Group group)
3972                    throws PortalException {
3973    
3974                    // User role
3975    
3976                    Role role = roleLocalService.getRole(
3977                            group.getCompanyId(), RoleConstants.USER);
3978    
3979                    setRolePermissions(
3980                            group, role, Layout.class.getName(),
3981                            new String[] {ActionKeys.VIEW});
3982    
3983                    setRolePermissions(
3984                            group, role, "com.liferay.portlet.blogs",
3985                            new String[] {
3986                                    ActionKeys.ADD_ENTRY, ActionKeys.PERMISSIONS,
3987                                    ActionKeys.SUBSCRIBE
3988                            });
3989    
3990                    // Power User role
3991    
3992                    role = roleLocalService.getRole(
3993                            group.getCompanyId(), RoleConstants.POWER_USER);
3994    
3995                    List<Portlet> portlets = portletLocalService.getPortlets(
3996                            group.getCompanyId(), false, false);
3997    
3998                    for (Portlet portlet : portlets) {
3999                            List<String> actions =
4000                                    ResourceActionsUtil.getPortletResourceActions(
4001                                            portlet.getPortletId());
4002    
4003                            String controlPanelEntryCategory = GetterUtil.getString(
4004                                    portlet.getControlPanelEntryCategory());
4005    
4006                            if (actions.contains(ActionKeys.ACCESS_IN_CONTROL_PANEL) &&
4007                                    controlPanelEntryCategory.startsWith(
4008                                            PortletCategoryKeys.SITE_ADMINISTRATION)) {
4009    
4010                                    setRolePermissions(
4011                                            group, role, portlet.getPortletId(),
4012                                            new String[] {ActionKeys.ACCESS_IN_CONTROL_PANEL});
4013                            }
4014                    }
4015    
4016                    setRolePermissions(
4017                            group, role, Group.class.getName(),
4018                            new String[] {
4019                                    ActionKeys.MANAGE_LAYOUTS, ActionKeys.VIEW_SITE_ADMINISTRATION
4020                            });
4021    
4022                    setRolePermissions(group, role, "com.liferay.portlet.asset");
4023                    setRolePermissions(group, role, "com.liferay.portlet.blogs");
4024                    setRolePermissions(group, role, "com.liferay.portlet.bookmarks");
4025                    setRolePermissions(group, role, "com.liferay.portlet.documentlibrary");
4026                    setRolePermissions(group, role, "com.liferay.portlet.imagegallery");
4027                    setRolePermissions(group, role, "com.liferay.portlet.journal");
4028                    setRolePermissions(group, role, "com.liferay.portlet.messageboards");
4029                    setRolePermissions(group, role, "com.liferay.portlet.wiki");
4030            }
4031    
4032            protected boolean isParentGroup(long parentGroupId, long groupId)
4033                    throws PortalException {
4034    
4035                    // Return true if parentGroupId is among the parent groups of groupId
4036    
4037                    if (groupId == GroupConstants.DEFAULT_PARENT_GROUP_ID) {
4038                            return false;
4039                    }
4040    
4041                    Group group = groupPersistence.findByPrimaryKey(groupId);
4042    
4043                    String treePath = group.getTreePath();
4044    
4045                    if (treePath.contains(
4046                                    StringPool.SLASH + parentGroupId + StringPool.SLASH)) {
4047    
4048                            return true;
4049                    }
4050                    else {
4051                            return false;
4052                    }
4053            }
4054    
4055            protected boolean isStaging(ServiceContext serviceContext) {
4056                    if (serviceContext != null) {
4057                            return ParamUtil.getBoolean(serviceContext, "staging");
4058                    }
4059    
4060                    return false;
4061            }
4062    
4063            protected boolean isUseComplexSQL(long[] classNameIds) {
4064                    if (ArrayUtil.isEmpty(classNameIds)) {
4065                            return true;
4066                    }
4067    
4068                    if (_complexSQLClassNameIds == null) {
4069                            String[] complexSQLClassNames =
4070                                    PropsValues.GROUPS_COMPLEX_SQL_CLASS_NAMES;
4071    
4072                            long[] complexSQLClassNameIds =
4073                                    new long[complexSQLClassNames.length];
4074    
4075                            for (int i = 0; i < complexSQLClassNames.length; i++) {
4076                                    String complexSQLClassName = complexSQLClassNames[i];
4077    
4078                                    complexSQLClassNameIds[i] =
4079                                            classNameLocalService.getClassNameId(complexSQLClassName);
4080                            }
4081    
4082                            _complexSQLClassNameIds = complexSQLClassNameIds;
4083                    }
4084    
4085                    for (long classNameId : classNameIds) {
4086                            if (ArrayUtil.contains(_complexSQLClassNameIds, classNameId)) {
4087                                    return true;
4088                            }
4089                    }
4090    
4091                    return false;
4092            }
4093    
4094            protected boolean matches(String s, String[] keywords) {
4095                    if ((keywords == null) ||
4096                            ((keywords.length == 1) && (keywords[0] == null))) {
4097    
4098                            return true;
4099                    }
4100    
4101                    for (String keyword : keywords) {
4102                            if (StringUtil.wildcardMatches(
4103                                            s, keyword, CharPool.UNDERLINE, CharPool.PERCENT,
4104                                            CharPool.BACK_SLASH, false)) {
4105    
4106                                    return true;
4107                            }
4108                    }
4109    
4110                    return false;
4111            }
4112    
4113            protected void setCompanyPermissions(
4114                            Role role, String name, String[] actionIds)
4115                    throws PortalException {
4116    
4117                    if (resourceBlockLocalService.isSupported(name)) {
4118                            resourceBlockLocalService.setCompanyScopePermissions(
4119                                    role.getCompanyId(), name, role.getRoleId(),
4120                                    Arrays.asList(actionIds));
4121                    }
4122                    else {
4123                            resourcePermissionLocalService.setResourcePermissions(
4124                                    role.getCompanyId(), name, ResourceConstants.SCOPE_COMPANY,
4125                                    String.valueOf(role.getCompanyId()), role.getRoleId(),
4126                                    actionIds);
4127                    }
4128            }
4129    
4130            protected void setRolePermissions(Group group, Role role, String name)
4131                    throws PortalException {
4132    
4133                    List<String> actions = ResourceActionsUtil.getModelResourceActions(
4134                            name);
4135    
4136                    setRolePermissions(
4137                            group, role, name, actions.toArray(new String[actions.size()]));
4138            }
4139    
4140            protected void setRolePermissions(
4141                            Group group, Role role, String name, String[] actionIds)
4142                    throws PortalException {
4143    
4144                    if (resourceBlockLocalService.isSupported(name)) {
4145                            resourceBlockLocalService.setGroupScopePermissions(
4146                                    role.getCompanyId(), group.getGroupId(), name, role.getRoleId(),
4147                                    Arrays.asList(actionIds));
4148                    }
4149                    else {
4150                            resourcePermissionLocalService.setResourcePermissions(
4151                                    group.getCompanyId(), name, ResourceConstants.SCOPE_GROUP,
4152                                    String.valueOf(group.getGroupId()), role.getRoleId(),
4153                                    actionIds);
4154                    }
4155            }
4156    
4157            protected List<Group> sort(
4158                    Collection<Group> groups, int start, int end,
4159                    OrderByComparator<Group> obc) {
4160    
4161                    if (obc == null) {
4162                            obc = new GroupNameComparator(true);
4163                    }
4164    
4165                    List<Group> groupList = null;
4166    
4167                    if (groups instanceof List) {
4168                            groupList = (List<Group>)groups;
4169                    }
4170                    else {
4171                            groupList = new ArrayList<>(groups);
4172                    }
4173    
4174                    Collections.sort(groupList, obc);
4175    
4176                    return Collections.unmodifiableList(
4177                            ListUtil.subList(groupList, start, end));
4178            }
4179    
4180            protected void unscheduleStaging(Group group) {
4181                    try {
4182    
4183                            // Remote publishing
4184    
4185                            String groupName = StagingUtil.getSchedulerGroupName(
4186                                    DestinationNames.LAYOUTS_REMOTE_PUBLISHER, group.getGroupId());
4187    
4188                            SchedulerEngineHelperUtil.delete(groupName, StorageType.PERSISTED);
4189    
4190                            long liveGroupId = 0;
4191                            long stagingGroupId = 0;
4192    
4193                            if (group.isStagingGroup()) {
4194                                    liveGroupId = group.getLiveGroupId();
4195    
4196                                    stagingGroupId = group.getGroupId();
4197                            }
4198                            else if (group.hasStagingGroup()) {
4199                                    liveGroupId = group.getGroupId();
4200    
4201                                    stagingGroupId = group.getStagingGroup().getGroupId();
4202                            }
4203    
4204                            if ((liveGroupId != 0) && (stagingGroupId != 0)) {
4205    
4206                                    // Publish to live
4207    
4208                                    groupName = StagingUtil.getSchedulerGroupName(
4209                                            DestinationNames.LAYOUTS_LOCAL_PUBLISHER, liveGroupId);
4210    
4211                                    SchedulerEngineHelperUtil.delete(
4212                                            groupName, StorageType.PERSISTED);
4213    
4214                                    // Copy from live
4215    
4216                                    groupName = StagingUtil.getSchedulerGroupName(
4217                                            DestinationNames.LAYOUTS_LOCAL_PUBLISHER, stagingGroupId);
4218    
4219                                    SchedulerEngineHelperUtil.delete(
4220                                            groupName, StorageType.PERSISTED);
4221                            }
4222                    }
4223                    catch (Exception e) {
4224                            _log.error(
4225                                    "Unable to unschedule events for group: " + group.getGroupId());
4226                    }
4227            }
4228    
4229            protected void validateFriendlyURL(
4230                            long companyId, long groupId, long classNameId, long classPK,
4231                            String friendlyURL)
4232                    throws PortalException {
4233    
4234                    Company company = companyPersistence.findByPrimaryKey(companyId);
4235    
4236                    if (company.isSystem()) {
4237                            return;
4238                    }
4239    
4240                    if (Validator.isNull(friendlyURL)) {
4241                            return;
4242                    }
4243    
4244                    int exceptionType = LayoutImpl.validateFriendlyURL(friendlyURL);
4245    
4246                    if (exceptionType != -1) {
4247                            throw new GroupFriendlyURLException(exceptionType);
4248                    }
4249    
4250                    Group group = groupPersistence.fetchByC_F(companyId, friendlyURL);
4251    
4252                    if ((group != null) && (group.getGroupId() != groupId)) {
4253                            GroupFriendlyURLException gfurle = new GroupFriendlyURLException(
4254                                    GroupFriendlyURLException.DUPLICATE);
4255    
4256                            gfurle.setDuplicateClassPK(group.getGroupId());
4257                            gfurle.setDuplicateClassName(Group.class.getName());
4258    
4259                            throw gfurle;
4260                    }
4261    
4262                    String groupIdFriendlyURL = friendlyURL.substring(1);
4263    
4264                    if (Validator.isNumber(groupIdFriendlyURL)) {
4265                            long groupClassNameId = classNameLocalService.getClassNameId(
4266                                    Group.class);
4267    
4268                            if (((classNameId != groupClassNameId) &&
4269                                     !groupIdFriendlyURL.equals(String.valueOf(classPK)) &&
4270                                     !PropsValues.USERS_SCREEN_NAME_ALLOW_NUMERIC) ||
4271                                    ((classNameId == groupClassNameId) &&
4272                                     !groupIdFriendlyURL.equals(String.valueOf(groupId)))) {
4273    
4274                                    GroupFriendlyURLException gfurle =
4275                                            new GroupFriendlyURLException(
4276                                                    GroupFriendlyURLException.POSSIBLE_DUPLICATE);
4277    
4278                                    gfurle.setKeywordConflict(groupIdFriendlyURL);
4279    
4280                                    throw gfurle;
4281                            }
4282                    }
4283    
4284                    String screenName = friendlyURL.substring(1);
4285    
4286                    User user = userPersistence.fetchByC_SN(companyId, screenName);
4287    
4288                    if (user != null) {
4289                            long userClassNameId = classNameLocalService.getClassNameId(
4290                                    User.class);
4291    
4292                            if ((classNameId == userClassNameId) &&
4293                                    (classPK == user.getUserId())) {
4294                            }
4295                            else {
4296                                    GroupFriendlyURLException gfurle =
4297                                            new GroupFriendlyURLException(
4298                                                    GroupFriendlyURLException.DUPLICATE);
4299    
4300                                    gfurle.setDuplicateClassPK(user.getUserId());
4301                                    gfurle.setDuplicateClassName(User.class.getName());
4302    
4303                                    throw gfurle;
4304                            }
4305                    }
4306    
4307                    if (StringUtil.count(friendlyURL, StringPool.SLASH) > 1) {
4308                            throw new GroupFriendlyURLException(
4309                                    GroupFriendlyURLException.TOO_DEEP);
4310                    }
4311            }
4312    
4313            protected void validateGroupKey(
4314                            long groupId, long companyId, String groupKey, boolean site)
4315                    throws PortalException {
4316    
4317                    if (Validator.isNull(groupKey) || Validator.isNumber(groupKey) ||
4318                            groupKey.contains(StringPool.STAR) ||
4319                            groupKey.contains(ORGANIZATION_NAME_SUFFIX)) {
4320    
4321                            throw new GroupKeyException();
4322                    }
4323    
4324                    try {
4325                            Group group = groupFinder.findByC_GK(companyId, groupKey);
4326    
4327                            if ((groupId <= 0) || (group.getGroupId() != groupId)) {
4328                                    throw new DuplicateGroupException("{groupId=" + groupId + "}");
4329                            }
4330                    }
4331                    catch (NoSuchGroupException nsge) {
4332                    }
4333    
4334                    if (site) {
4335                            Company company = companyLocalService.getCompany(companyId);
4336    
4337                            if (groupKey.equals(company.getName())) {
4338                                    throw new DuplicateGroupException();
4339                            }
4340                    }
4341            }
4342    
4343            protected void validateInheritContent(
4344                            long parentGroupId, boolean inheritContent)
4345                    throws GroupInheritContentException {
4346    
4347                    if (!inheritContent) {
4348                            return;
4349                    }
4350    
4351                    if (parentGroupId == GroupConstants.DEFAULT_PARENT_GROUP_ID) {
4352                            throw new GroupInheritContentException();
4353                    }
4354    
4355                    Group parentGroup = groupPersistence.fetchByPrimaryKey(parentGroupId);
4356    
4357                    if (parentGroup.isInheritContent()) {
4358                            throw new GroupInheritContentException();
4359                    }
4360            }
4361    
4362            protected void validateLanguageIds(
4363                            String defaultLanguageId, String languageIds)
4364                    throws PortalException {
4365    
4366                    String[] languageIdsArray = StringUtil.split(languageIds);
4367    
4368                    for (String languageId : languageIdsArray) {
4369                            if (!LanguageUtil.isAvailableLocale(
4370                                            LocaleUtil.fromLanguageId(languageId))) {
4371    
4372                                    LocaleException le = new LocaleException(
4373                                            LocaleException.TYPE_DISPLAY_SETTINGS);
4374    
4375                                    le.setSourceAvailableLocales(
4376                                            LanguageUtil.getAvailableLocales());
4377                                    le.setTargetAvailableLocales(
4378                                            Arrays.asList(
4379                                                    LocaleUtil.fromLanguageIds(languageIdsArray)));
4380    
4381                                    throw le;
4382                            }
4383                    }
4384    
4385                    if (!ArrayUtil.contains(languageIdsArray, defaultLanguageId)) {
4386                            LocaleException le = new LocaleException(
4387                                    LocaleException.TYPE_DEFAULT);
4388    
4389                            le.setSourceAvailableLocales(LanguageUtil.getAvailableLocales());
4390                            le.setTargetAvailableLocales(
4391                                    Arrays.asList(LocaleUtil.fromLanguageIds(languageIdsArray)));
4392    
4393                            throw le;
4394                    }
4395            }
4396    
4397            protected void validateParentGroup(long groupId, long parentGroupId)
4398                    throws PortalException {
4399    
4400                    if (parentGroupId == GroupConstants.DEFAULT_PARENT_GROUP_ID) {
4401                            return;
4402                    }
4403    
4404                    if (groupId == parentGroupId) {
4405                            throw new GroupParentException.MustNotBeOwnParent(groupId);
4406                    }
4407    
4408                    Group group = groupPersistence.fetchByPrimaryKey(groupId);
4409    
4410                    if (group == null) {
4411                            return;
4412                    }
4413    
4414                    if ((groupId > 0) &&
4415                            (parentGroupId != GroupConstants.DEFAULT_PARENT_GROUP_ID)) {
4416    
4417                            // Prevent circular groupal references
4418    
4419                            if (isParentGroup(groupId, parentGroupId)) {
4420                                    throw new GroupParentException.MustNotHaveChildParent(
4421                                            groupId, parentGroupId);
4422                            }
4423                    }
4424    
4425                    Group parentGroup = groupPersistence.findByPrimaryKey(parentGroupId);
4426    
4427                    if (group.isStagingGroup()) {
4428                            long stagingGroupId = parentGroup.getStagingGroup().getGroupId();
4429    
4430                            if (groupId == stagingGroupId) {
4431                                    throw new GroupParentException.MustNotHaveStagingParent(
4432                                            groupId, stagingGroupId);
4433                            }
4434                    }
4435            }
4436    
4437            protected File publicLARFile;
4438    
4439            private static final Log _log = LogFactoryUtil.getLog(
4440                    GroupLocalServiceImpl.class);
4441    
4442            private volatile long[] _classNameIds;
4443            private volatile long[] _complexSQLClassNameIds;
4444            private final Map<String, Group> _systemGroupsMap = new HashMap<>();
4445    
4446    }