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