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