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