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