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