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