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