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.DuplicateUserGroupException;
018    import com.liferay.portal.NoSuchUserGroupException;
019    import com.liferay.portal.RequiredUserGroupException;
020    import com.liferay.portal.UserGroupNameException;
021    import com.liferay.portal.kernel.dao.orm.QueryUtil;
022    import com.liferay.portal.kernel.exception.PortalException;
023    import com.liferay.portal.kernel.exception.SystemException;
024    import com.liferay.portal.kernel.search.BaseModelSearchResult;
025    import com.liferay.portal.kernel.search.Hits;
026    import com.liferay.portal.kernel.search.Indexer;
027    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
028    import com.liferay.portal.kernel.search.QueryConfig;
029    import com.liferay.portal.kernel.search.SearchContext;
030    import com.liferay.portal.kernel.search.SearchException;
031    import com.liferay.portal.kernel.search.Sort;
032    import com.liferay.portal.kernel.systemevent.SystemEvent;
033    import com.liferay.portal.kernel.util.CharPool;
034    import com.liferay.portal.kernel.util.GetterUtil;
035    import com.liferay.portal.kernel.util.MapUtil;
036    import com.liferay.portal.kernel.util.OrderByComparator;
037    import com.liferay.portal.kernel.util.SetUtil;
038    import com.liferay.portal.kernel.util.Validator;
039    import com.liferay.portal.kernel.workflow.WorkflowConstants;
040    import com.liferay.portal.model.Group;
041    import com.liferay.portal.model.GroupConstants;
042    import com.liferay.portal.model.ResourceConstants;
043    import com.liferay.portal.model.SystemEventConstants;
044    import com.liferay.portal.model.Team;
045    import com.liferay.portal.model.User;
046    import com.liferay.portal.model.UserGroup;
047    import com.liferay.portal.model.UserGroupConstants;
048    import com.liferay.portal.security.auth.PrincipalThreadLocal;
049    import com.liferay.portal.security.exportimport.UserGroupImportTransactionThreadLocal;
050    import com.liferay.portal.security.permission.PermissionCacheUtil;
051    import com.liferay.portal.service.ServiceContext;
052    import com.liferay.portal.service.base.UserGroupLocalServiceBaseImpl;
053    import com.liferay.portal.util.PropsValues;
054    import com.liferay.portlet.exportimport.configuration.ExportImportConfigurationConstants;
055    import com.liferay.portlet.exportimport.configuration.ExportImportConfigurationSettingsMapFactory;
056    import com.liferay.portlet.exportimport.lar.ExportImportHelperUtil;
057    import com.liferay.portlet.exportimport.lar.PortletDataHandlerKeys;
058    import com.liferay.portlet.exportimport.lar.UserIdStrategy;
059    import com.liferay.portlet.exportimport.model.ExportImportConfiguration;
060    import com.liferay.portlet.usersadmin.util.UsersAdminUtil;
061    
062    import java.io.File;
063    import java.io.Serializable;
064    
065    import java.util.ArrayList;
066    import java.util.Collections;
067    import java.util.HashMap;
068    import java.util.LinkedHashMap;
069    import java.util.List;
070    import java.util.Map;
071    import java.util.Set;
072    
073    /**
074     * Provides the local service for accessing, adding, deleting, and updating user
075     * groups.
076     *
077     * @author Charles May
078     */
079    public class UserGroupLocalServiceImpl extends UserGroupLocalServiceBaseImpl {
080    
081            /**
082             * Adds the user groups to the group.
083             *
084             * @param groupId the primary key of the group
085             * @param userGroupIds the primary keys of the user groups
086             */
087            @Override
088            public void addGroupUserGroups(long groupId, long[] userGroupIds) {
089                    groupPersistence.addUserGroups(groupId, userGroupIds);
090    
091                    PermissionCacheUtil.clearCache();
092            }
093    
094            /**
095             * Adds the user groups to the team.
096             *
097             * @param teamId the primary key of the team
098             * @param userGroupIds the primary keys of the user groups
099             */
100            @Override
101            public void addTeamUserGroups(long teamId, long[] userGroupIds) {
102                    teamPersistence.addUserGroups(teamId, userGroupIds);
103    
104                    PermissionCacheUtil.clearCache();
105            }
106    
107            /**
108             * Adds a user group.
109             *
110             * <p>
111             * This method handles the creation and bookkeeping of the user group,
112             * including its resources, metadata, and internal data structures. It is
113             * not necessary to make subsequent calls to setup default groups and
114             * resources for the user group.
115             * </p>
116             *
117             * @param      userId the primary key of the user
118             * @param      companyId the primary key of the user group's company
119             * @param      name the user group's name
120             * @param      description the user group's description
121             * @return     the user group
122             * @deprecated As of 6.2.0, replaced by {@link #addUserGroup(long, long,
123             *             String, String, ServiceContext)}
124             */
125            @Deprecated
126            @Override
127            public UserGroup addUserGroup(
128                            long userId, long companyId, String name, String description)
129                    throws PortalException {
130    
131                    return addUserGroup(userId, companyId, name, description, null);
132            }
133    
134            /**
135             * Adds a user group.
136             *
137             * <p>
138             * This method handles the creation and bookkeeping of the user group,
139             * including its resources, metadata, and internal data structures. It is
140             * not necessary to make subsequent calls to setup default groups and
141             * resources for the user group.
142             * </p>
143             *
144             * @param  userId the primary key of the user
145             * @param  companyId the primary key of the user group's company
146             * @param  name the user group's name
147             * @param  description the user group's description
148             * @param  serviceContext the service context to be applied (optionally
149             *         <code>null</code>). Can set expando bridge attributes for the
150             *         user group.
151             * @return the user group
152             */
153            @Override
154            public UserGroup addUserGroup(
155                            long userId, long companyId, String name, String description,
156                            ServiceContext serviceContext)
157                    throws PortalException {
158    
159                    // User group
160    
161                    validate(0, companyId, name);
162    
163                    User user = userPersistence.findByPrimaryKey(userId);
164    
165                    long userGroupId = counterLocalService.increment();
166    
167                    UserGroup userGroup = userGroupPersistence.create(userGroupId);
168    
169                    if (serviceContext != null) {
170                            userGroup.setUuid(serviceContext.getUuid());
171                    }
172    
173                    userGroup.setCompanyId(companyId);
174                    userGroup.setUserId(user.getUserId());
175                    userGroup.setUserName(user.getFullName());
176                    userGroup.setParentUserGroupId(
177                            UserGroupConstants.DEFAULT_PARENT_USER_GROUP_ID);
178                    userGroup.setName(name);
179                    userGroup.setDescription(description);
180                    userGroup.setAddedByLDAPImport(
181                            UserGroupImportTransactionThreadLocal.isOriginatesFromImport());
182                    userGroup.setExpandoBridgeAttributes(serviceContext);
183    
184                    userGroupPersistence.update(userGroup);
185    
186                    // Group
187    
188                    groupLocalService.addGroup(
189                            userId, GroupConstants.DEFAULT_PARENT_GROUP_ID,
190                            UserGroup.class.getName(), userGroup.getUserGroupId(),
191                            GroupConstants.DEFAULT_LIVE_GROUP_ID,
192                            getLocalizationMap(String.valueOf(userGroupId)), null, 0, true,
193                            GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION, null, false, true,
194                            null);
195    
196                    // Resources
197    
198                    resourceLocalService.addResources(
199                            companyId, 0, userId, UserGroup.class.getName(),
200                            userGroup.getUserGroupId(), false, false, false);
201    
202                    // Indexer
203    
204                    Indexer<UserGroup> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
205                            UserGroup.class);
206    
207                    indexer.reindex(userGroup);
208    
209                    return userGroup;
210            }
211    
212            /**
213             * Clears all associations between the user and its user groups and clears
214             * the permissions cache.
215             *
216             * @param userId the primary key of the user
217             */
218            @Override
219            public void clearUserUserGroups(long userId) {
220                    userPersistence.clearUserGroups(userId);
221    
222                    PermissionCacheUtil.clearCache(userId);
223            }
224    
225            /**
226             * Copies the user group's layout to the user.
227             *
228             * @param      userGroupId the primary key of the user group
229             * @param      userId the primary key of the user
230             * @deprecated As of 6.2.0
231             */
232            @Deprecated
233            @Override
234            public void copyUserGroupLayouts(long userGroupId, long userId)
235                    throws PortalException {
236    
237                    Map<String, String[]> parameterMap = getLayoutTemplatesParameters();
238    
239                    File[] files = exportLayouts(userGroupId, parameterMap);
240    
241                    try {
242                            importLayouts(userId, parameterMap, files[0], files[1]);
243                    }
244                    finally {
245                            if (files[0] != null) {
246                                    files[0].delete();
247                            }
248    
249                            if (files[1] != null) {
250                                    files[1].delete();
251                            }
252                    }
253            }
254    
255            /**
256             * Copies the user group's layouts to the users who are not already members
257             * of the user group.
258             *
259             * @param      userGroupId the primary key of the user group
260             * @param      userIds the primary keys of the users
261             * @deprecated As of 6.1.0
262             */
263            @Deprecated
264            @Override
265            public void copyUserGroupLayouts(long userGroupId, long[] userIds)
266                    throws PortalException {
267    
268                    Map<String, String[]> parameterMap = getLayoutTemplatesParameters();
269    
270                    File[] files = exportLayouts(userGroupId, parameterMap);
271    
272                    try {
273                            for (long userId : userIds) {
274                                    if (!userGroupPersistence.containsUser(userGroupId, userId)) {
275                                            importLayouts(userId, parameterMap, files[0], files[1]);
276                                    }
277                            }
278                    }
279                    finally {
280                            if (files[0] != null) {
281                                    files[0].delete();
282                            }
283    
284                            if (files[1] != null) {
285                                    files[1].delete();
286                            }
287                    }
288            }
289    
290            /**
291             * Copies the user groups' layouts to the user.
292             *
293             * @param      userGroupIds the primary keys of the user groups
294             * @param      userId the primary key of the user
295             * @deprecated As of 6.1.0
296             */
297            @Deprecated
298            @Override
299            public void copyUserGroupLayouts(long[] userGroupIds, long userId)
300                    throws PortalException {
301    
302                    for (long userGroupId : userGroupIds) {
303                            if (!userGroupPersistence.containsUser(userGroupId, userId)) {
304                                    copyUserGroupLayouts(userGroupId, userId);
305                            }
306                    }
307            }
308    
309            /**
310             * Deletes the user group.
311             *
312             * @param  userGroupId the primary key of the user group
313             * @return the deleted user group
314             */
315            @Override
316            public UserGroup deleteUserGroup(long userGroupId) throws PortalException {
317                    UserGroup userGroup = userGroupPersistence.findByPrimaryKey(
318                            userGroupId);
319    
320                    return userGroupLocalService.deleteUserGroup(userGroup);
321            }
322    
323            /**
324             * Deletes the user group.
325             *
326             * @param  userGroup the user group
327             * @return the deleted user group
328             */
329            @Override
330            @SystemEvent(
331                    action = SystemEventConstants.ACTION_SKIP,
332                    type = SystemEventConstants.TYPE_DELETE
333            )
334            public UserGroup deleteUserGroup(UserGroup userGroup)
335                    throws PortalException {
336    
337                    int count = userLocalService.getUserGroupUsersCount(
338                            userGroup.getUserGroupId(), WorkflowConstants.STATUS_APPROVED);
339    
340                    if (count > 0) {
341                            throw new RequiredUserGroupException();
342                    }
343    
344                    // Expando
345    
346                    expandoRowLocalService.deleteRows(userGroup.getUserGroupId());
347    
348                    // Group
349    
350                    Group group = userGroup.getGroup();
351    
352                    groupLocalService.deleteGroup(group);
353    
354                    // User group roles
355    
356                    userGroupGroupRoleLocalService.deleteUserGroupGroupRolesByUserGroupId(
357                            userGroup.getUserGroupId());
358    
359                    // Resources
360    
361                    resourceLocalService.deleteResource(
362                            userGroup.getCompanyId(), UserGroup.class.getName(),
363                            ResourceConstants.SCOPE_INDIVIDUAL, userGroup.getUserGroupId());
364    
365                    // User group
366    
367                    userGroupPersistence.remove(userGroup);
368    
369                    // Permission cache
370    
371                    PermissionCacheUtil.clearCache();
372    
373                    return userGroup;
374            }
375    
376            @Override
377            public void deleteUserGroups(long companyId) throws PortalException {
378                    List<UserGroup> userGroups = userGroupPersistence.findByCompanyId(
379                            companyId);
380    
381                    for (UserGroup userGroup : userGroups) {
382                            userGroupLocalService.deleteUserGroup(userGroup);
383                    }
384            }
385    
386            @Override
387            public UserGroup fetchUserGroup(long companyId, String name) {
388                    return userGroupPersistence.fetchByC_N(companyId, name);
389            }
390    
391            @Override
392            public List<UserGroup> getGroupUserUserGroups(long groupId, long userId)
393                    throws PortalException {
394    
395                    long[] groupUserGroupIds = groupPersistence.getUserGroupPrimaryKeys(
396                            groupId);
397    
398                    if (groupUserGroupIds.length == 0) {
399                            return Collections.emptyList();
400                    }
401    
402                    long[] userUserGroupIds = userPersistence.getUserGroupPrimaryKeys(
403                            userId);
404    
405                    if (userUserGroupIds.length == 0) {
406                            return Collections.emptyList();
407                    }
408    
409                    Set<Long> userGroupIds = SetUtil.intersect(
410                            groupUserGroupIds, userUserGroupIds);
411    
412                    if (userGroupIds.isEmpty()) {
413                            return Collections.emptyList();
414                    }
415    
416                    List<UserGroup> userGroups = new ArrayList<>(userGroupIds.size());
417    
418                    for (Long userGroupId : userGroupIds) {
419                            userGroups.add(userGroupPersistence.findByPrimaryKey(userGroupId));
420                    }
421    
422                    return userGroups;
423            }
424    
425            /**
426             * Returns the user group with the name.
427             *
428             * @param  companyId the primary key of the user group's company
429             * @param  name the user group's name
430             * @return Returns the user group with the name
431             */
432            @Override
433            public UserGroup getUserGroup(long companyId, String name)
434                    throws PortalException {
435    
436                    return userGroupPersistence.findByC_N(companyId, name);
437            }
438    
439            /**
440             * Returns all the user groups belonging to the company.
441             *
442             * @param  companyId the primary key of the user groups' company
443             * @return the user groups belonging to the company
444             */
445            @Override
446            public List<UserGroup> getUserGroups(long companyId) {
447                    return userGroupPersistence.findByCompanyId(companyId);
448            }
449    
450            /**
451             * Returns all the user groups with the primary keys.
452             *
453             * @param  userGroupIds the primary keys of the user groups
454             * @return the user groups with the primary keys
455             */
456            @Override
457            public List<UserGroup> getUserGroups(long[] userGroupIds)
458                    throws PortalException {
459    
460                    List<UserGroup> userGroups = new ArrayList<>(userGroupIds.length);
461    
462                    for (long userGroupId : userGroupIds) {
463                            UserGroup userGroup = getUserGroup(userGroupId);
464    
465                            userGroups.add(userGroup);
466                    }
467    
468                    return userGroups;
469            }
470    
471            /**
472             * Returns an ordered range of all the user groups that match the keywords.
473             *
474             * <p>
475             * Useful when paginating results. Returns a maximum of <code>end -
476             * start</code> instances. <code>start</code> and <code>end</code> are not
477             * primary keys, they are indexes in the result set. Thus, <code>0</code>
478             * refers to the first result in the set. Setting both <code>start</code>
479             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
480             * result set.
481             * </p>
482             *
483             * @param  companyId the primary key of the user group's company
484             * @param  keywords the keywords (space separated), which may occur in the
485             *         user group's name or description (optionally <code>null</code>)
486             * @param  params the finder params (optionally <code>null</code>). For more
487             *         information see {@link
488             *         com.liferay.portal.service.persistence.UserGroupFinder}
489             * @param  start the lower bound of the range of user groups to return
490             * @param  end the upper bound of the range of user groups to return (not
491             *         inclusive)
492             * @param  obc the comparator to order the user groups (optionally
493             *         <code>null</code>)
494             * @return the matching user groups ordered by comparator <code>obc</code>
495             * @see    com.liferay.portal.service.persistence.UserGroupFinder
496             */
497            @Override
498            public List<UserGroup> search(
499                    long companyId, String keywords, LinkedHashMap<String, Object> params,
500                    int start, int end, OrderByComparator<UserGroup> obc) {
501    
502                    return userGroupFinder.findByKeywords(
503                            companyId, keywords, params, start, end, obc);
504            }
505    
506            /**
507             * Returns an ordered range of all the user groups that match the keywords,
508             * using the indexer. It is preferable to use this method instead of the
509             * non-indexed version whenever possible for performance reasons.
510             *
511             * <p>
512             * Useful when paginating results. Returns a maximum of <code>end -
513             * start</code> instances. <code>start</code> and <code>end</code> are not
514             * primary keys, they are indexes in the result set. Thus, <code>0</code>
515             * refers to the first result in the set. Setting both <code>start</code>
516             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
517             * result set.
518             * </p>
519             *
520             * @param  companyId the primary key of the user group's company
521             * @param  keywords the keywords (space separated), which may occur in the
522             *         user group's name or description (optionally <code>null</code>)
523             * @param  params the finder params (optionally <code>null</code>). For more
524             *         information see {@link
525             *         com.liferay.portlet.usergroupsadmin.util.UserGroupIndexer}
526             * @param  start the lower bound of the range of user groups to return
527             * @param  end the upper bound of the range of user groups to return (not
528             *         inclusive)
529             * @param  sort the field and direction by which to sort (optionally
530             *         <code>null</code>)
531             * @return the matching user groups ordered by sort
532             * @see    com.liferay.portlet.usergroupsadmin.util.UserGroupIndexer
533             */
534            @Override
535            public Hits search(
536                    long companyId, String keywords, LinkedHashMap<String, Object> params,
537                    int start, int end, Sort sort) {
538    
539                    String name = null;
540                    String description = null;
541                    boolean andOperator = false;
542    
543                    if (Validator.isNotNull(keywords)) {
544                            name = keywords;
545                            description = keywords;
546                    }
547                    else {
548                            andOperator = true;
549                    }
550    
551                    if (params != null) {
552                            params.put("keywords", keywords);
553                    }
554    
555                    return search(
556                            companyId, name, description, params, andOperator, start, end,
557                            sort);
558            }
559    
560            /**
561             * Returns an ordered range of all the user groups that match the name and
562             * description.
563             *
564             * <p>
565             * Useful when paginating results. Returns a maximum of <code>end -
566             * start</code> instances. <code>start</code> and <code>end</code> are not
567             * primary keys, they are indexes in the result set. Thus, <code>0</code>
568             * refers to the first result in the set. Setting both <code>start</code>
569             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
570             * result set.
571             * </p>
572             *
573             * @param  companyId the primary key of the user group's company
574             * @param  name the user group's name (optionally <code>null</code>)
575             * @param  description the user group's description (optionally
576             *         <code>null</code>)
577             * @param  params the finder params (optionally <code>null</code>). For more
578             *         information see {@link
579             *         com.liferay.portal.service.persistence.UserGroupFinder}
580             * @param  andOperator whether every field must match its keywords or just
581             *         one field
582             * @param  start the lower bound of the range of user groups to return
583             * @param  end the upper bound of the range of user groups to return (not
584             *         inclusive)
585             * @param  obc the comparator to order the user groups (optionally
586             *         <code>null</code>)
587             * @return the matching user groups ordered by comparator <code>obc</code>
588             * @see    com.liferay.portal.service.persistence.UserGroupFinder
589             */
590            @Override
591            public List<UserGroup> search(
592                    long companyId, String name, String description,
593                    LinkedHashMap<String, Object> params, boolean andOperator, int start,
594                    int end, OrderByComparator<UserGroup> obc) {
595    
596                    return userGroupFinder.findByC_N_D(
597                            companyId, name, description, params, andOperator, start, end, obc);
598            }
599    
600            /**
601             * Returns an ordered range of all the user groups that match the name and
602             * description. It is preferable to use this method instead of the
603             * non-indexed version whenever possible for performance reasons.
604             *
605             * <p>
606             * Useful when paginating results. Returns a maximum of <code>end -
607             * start</code> instances. <code>start</code> and <code>end</code> are not
608             * primary keys, they are indexes in the result set. Thus, <code>0</code>
609             * refers to the first result in the set. Setting both <code>start</code>
610             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
611             * result set.
612             * </p>
613             *
614             * @param  companyId the primary key of the user group's company
615             * @param  name the user group's name (optionally <code>null</code>)
616             * @param  description the user group's description (optionally
617             *         <code>null</code>)
618             * @param  params the finder params (optionally <code>null</code>). For more
619             *         information see {@link
620             *         com.liferay.portlet.usergroupsadmin.util.UserGroupIndexer}
621             * @param  andSearch whether every field must match its keywords or just one
622             *         field
623             * @param  start the lower bound of the range of user groups to return
624             * @param  end the upper bound of the range of user groups to return (not
625             *         inclusive)
626             * @param  sort the field and direction by which to sort (optionally
627             *         <code>null</code>)
628             * @return the matching user groups ordered by sort
629             * @see    com.liferay.portal.service.persistence.UserGroupFinder
630             */
631            @Override
632            public Hits search(
633                    long companyId, String name, String description,
634                    LinkedHashMap<String, Object> params, boolean andSearch, int start,
635                    int end, Sort sort) {
636    
637                    try {
638                            Indexer<UserGroup> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
639                                    UserGroup.class);
640    
641                            SearchContext searchContext = buildSearchContext(
642                                    companyId, name, description, params, andSearch, start, end,
643                                    sort);
644    
645                            return indexer.search(searchContext);
646                    }
647                    catch (Exception e) {
648                            throw new SystemException(e);
649                    }
650            }
651    
652            /**
653             * Returns the number of user groups that match the keywords
654             *
655             * @param  companyId the primary key of the user group's company
656             * @param  keywords the keywords (space separated), which may occur in the
657             *         user group's name or description (optionally <code>null</code>)
658             * @param  params the finder params (optionally <code>null</code>). For more
659             *         information see {@link
660             *         com.liferay.portal.service.persistence.UserGroupFinder}
661             * @return the number of matching user groups
662             * @see    com.liferay.portal.service.persistence.UserGroupFinder
663             */
664            @Override
665            public int searchCount(
666                    long companyId, String keywords, LinkedHashMap<String, Object> params) {
667    
668                    Indexer<?> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
669                            UserGroup.class);
670    
671                    if (!indexer.isIndexerEnabled() ||
672                            !PropsValues.USER_GROUPS_SEARCH_WITH_INDEX ||
673                            isUseCustomSQL(params)) {
674    
675                            return userGroupFinder.countByKeywords(companyId, keywords, params);
676                    }
677    
678                    String name = null;
679                    String description = null;
680                    boolean andOperator = false;
681    
682                    if (Validator.isNotNull(keywords)) {
683                            name = keywords;
684                            description = keywords;
685                    }
686                    else {
687                            andOperator = true;
688                    }
689    
690                    if (params != null) {
691                            params.put("keywords", keywords);
692                    }
693    
694                    try {
695                            SearchContext searchContext = buildSearchContext(
696                                    companyId, name, description, params, andOperator,
697                                    QueryUtil.ALL_POS, QueryUtil.ALL_POS, null);
698    
699                            return (int)indexer.searchCount(searchContext);
700                    }
701                    catch (Exception e) {
702                            throw new SystemException(e);
703                    }
704            }
705    
706            /**
707             * Returns the number of user groups that match the name and description.
708             *
709             * @param  companyId the primary key of the user group's company
710             * @param  name the user group's name (optionally <code>null</code>)
711             * @param  description the user group's description (optionally
712             *         <code>null</code>)
713             * @param  params the finder params (optionally <code>null</code>). For more
714             *         information see {@link
715             *         com.liferay.portal.service.persistence.UserGroupFinder}
716             * @param  andOperator whether every field must match its keywords or just
717             *         one field
718             * @return the number of matching user groups
719             * @see    com.liferay.portal.service.persistence.UserGroupFinder
720             */
721            @Override
722            public int searchCount(
723                    long companyId, String name, String description,
724                    LinkedHashMap<String, Object> params, boolean andOperator) {
725    
726                    Indexer<?> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
727                            UserGroup.class);
728    
729                    if (!indexer.isIndexerEnabled() ||
730                            !PropsValues.USER_GROUPS_SEARCH_WITH_INDEX ||
731                            isUseCustomSQL(params)) {
732    
733                            return userGroupFinder.countByC_N_D(
734                                    companyId, name, description, params, andOperator);
735                    }
736    
737                    try {
738                            SearchContext searchContext = buildSearchContext(
739                                    companyId, name, description, params, true, QueryUtil.ALL_POS,
740                                    QueryUtil.ALL_POS, null);
741    
742                            return (int)indexer.searchCount(searchContext);
743                    }
744                    catch (Exception e) {
745                            throw new SystemException(e);
746                    }
747            }
748    
749            @Override
750            public BaseModelSearchResult<UserGroup> searchUserGroups(
751                            long companyId, String keywords,
752                            LinkedHashMap<String, Object> params, int start, int end, Sort sort)
753                    throws PortalException {
754    
755                    String name = null;
756                    String description = null;
757                    boolean andOperator = false;
758    
759                    if (Validator.isNotNull(keywords)) {
760                            name = keywords;
761                            description = keywords;
762                    }
763                    else {
764                            andOperator = true;
765                    }
766    
767                    if (params != null) {
768                            params.put("keywords", keywords);
769                    }
770    
771                    return searchUserGroups(
772                            companyId, name, description, params, andOperator, start, end,
773                            sort);
774            }
775    
776            @Override
777            public BaseModelSearchResult<UserGroup> searchUserGroups(
778                            long companyId, String name, String description,
779                            LinkedHashMap<String, Object> params, boolean andSearch, int start,
780                            int end, Sort sort)
781                    throws PortalException {
782    
783                    Indexer<UserGroup> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
784                            UserGroup.class);
785    
786                    SearchContext searchContext = buildSearchContext(
787                            companyId, name, description, params, andSearch, start, end, sort);
788    
789                    for (int i = 0; i < 10; i++) {
790                            Hits hits = indexer.search(searchContext);
791    
792                            List<UserGroup> userGroups = UsersAdminUtil.getUserGroups(hits);
793    
794                            if (userGroups != null) {
795                                    return new BaseModelSearchResult<>(
796                                            userGroups, hits.getLength());
797                            }
798                    }
799    
800                    throw new SearchException(
801                            "Unable to fix the search index after 10 attempts");
802            }
803    
804            /**
805             * Sets the user groups associated with the user copying the user group
806             * layouts and removing and adding user group associations for the user as
807             * necessary.
808             *
809             * @param userId the primary key of the user
810             * @param userGroupIds the primary keys of the user groups
811             */
812            @Override
813            public void setUserUserGroups(long userId, long[] userGroupIds)
814                    throws PortalException {
815    
816                    if (PropsValues.USER_GROUPS_COPY_LAYOUTS_TO_USER_PERSONAL_SITE) {
817                            copyUserGroupLayouts(userGroupIds, userId);
818                    }
819    
820                    userPersistence.setUserGroups(userId, userGroupIds);
821    
822                    Indexer<User> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
823                            User.class);
824    
825                    User user = userLocalService.fetchUser(userId);
826    
827                    indexer.reindex(user);
828    
829                    PermissionCacheUtil.clearCache(userId);
830            }
831    
832            /**
833             * Removes the user groups from the group.
834             *
835             * @param groupId the primary key of the group
836             * @param userGroupIds the primary keys of the user groups
837             */
838            @Override
839            public void unsetGroupUserGroups(long groupId, long[] userGroupIds) {
840                    List<Team> teams = teamPersistence.findByGroupId(groupId);
841    
842                    for (Team team : teams) {
843                            teamPersistence.removeUserGroups(team.getTeamId(), userGroupIds);
844                    }
845    
846                    userGroupGroupRoleLocalService.deleteUserGroupGroupRoles(
847                            userGroupIds, groupId);
848    
849                    groupPersistence.removeUserGroups(groupId, userGroupIds);
850    
851                    PermissionCacheUtil.clearCache();
852            }
853    
854            /**
855             * Removes the user groups from the team.
856             *
857             * @param teamId the primary key of the team
858             * @param userGroupIds the primary keys of the user groups
859             */
860            @Override
861            public void unsetTeamUserGroups(long teamId, long[] userGroupIds) {
862                    teamPersistence.removeUserGroups(teamId, userGroupIds);
863    
864                    PermissionCacheUtil.clearCache();
865            }
866    
867            /**
868             * Updates the user group.
869             *
870             * @param      companyId the primary key of the user group's company
871             * @param      userGroupId the primary key of the user group
872             * @param      name the user group's name
873             * @param      description the user group's description
874             * @return     the user group
875             * @deprecated As of 6.2.0, replaced by {@link #updateUserGroup(long, long,
876             *             String, String, ServiceContext)}
877             */
878            @Deprecated
879            @Override
880            public UserGroup updateUserGroup(
881                            long companyId, long userGroupId, String name, String description)
882                    throws PortalException {
883    
884                    return updateUserGroup(companyId, userGroupId, name, description, null);
885            }
886    
887            /**
888             * Updates the user group.
889             *
890             * @param  companyId the primary key of the user group's company
891             * @param  userGroupId the primary key of the user group
892             * @param  name the user group's name
893             * @param  description the user group's description
894             * @param  serviceContext the service context to be applied (optionally
895             *         <code>null</code>). Can set expando bridge attributes for the
896             *         user group.
897             * @return the user group
898             */
899            @Override
900            public UserGroup updateUserGroup(
901                            long companyId, long userGroupId, String name, String description,
902                            ServiceContext serviceContext)
903                    throws PortalException {
904    
905                    // User group
906    
907                    validate(userGroupId, companyId, name);
908    
909                    UserGroup userGroup = userGroupPersistence.findByPrimaryKey(
910                            userGroupId);
911    
912                    userGroup.setName(name);
913                    userGroup.setDescription(description);
914                    userGroup.setExpandoBridgeAttributes(serviceContext);
915    
916                    userGroupPersistence.update(userGroup);
917    
918                    // Indexer
919    
920                    Indexer<UserGroup> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
921                            UserGroup.class);
922    
923                    indexer.reindex(userGroup);
924    
925                    return userGroup;
926            }
927    
928            protected SearchContext buildSearchContext(
929                    long companyId, String name, String description,
930                    LinkedHashMap<String, Object> params, boolean andSearch, int start,
931                    int end, Sort sort) {
932    
933                    SearchContext searchContext = new SearchContext();
934    
935                    searchContext.setAndSearch(andSearch);
936    
937                    Map<String, Serializable> attributes = new HashMap<>();
938    
939                    attributes.put("description", description);
940                    attributes.put("name", name);
941    
942                    searchContext.setAttributes(attributes);
943    
944                    searchContext.setCompanyId(companyId);
945                    searchContext.setEnd(end);
946    
947                    if (params != null) {
948                            String keywords = (String)params.remove("keywords");
949    
950                            if (Validator.isNotNull(keywords)) {
951                                    searchContext.setKeywords(keywords);
952                            }
953                    }
954    
955                    if (sort != null) {
956                            searchContext.setSorts(sort);
957                    }
958    
959                    searchContext.setStart(start);
960    
961                    QueryConfig queryConfig = searchContext.getQueryConfig();
962    
963                    queryConfig.setHighlightEnabled(false);
964                    queryConfig.setScoreEnabled(false);
965    
966                    return searchContext;
967            }
968    
969            protected File[] exportLayouts(
970                            long userGroupId, Map<String, String[]> parameterMap)
971                    throws PortalException {
972    
973                    File[] files = new File[2];
974    
975                    UserGroup userGroup = userGroupPersistence.findByPrimaryKey(
976                            userGroupId);
977    
978                    User user = userLocalService.getUser(
979                            GetterUtil.getLong(PrincipalThreadLocal.getName()));
980    
981                    Group group = userGroup.getGroup();
982    
983                    if (userGroup.hasPrivateLayouts()) {
984                            Map<String, Serializable> exportLayoutSettingsMap =
985                                    ExportImportConfigurationSettingsMapFactory.
986                                            buildExportLayoutSettingsMap(
987                                                    user, group.getGroupId(), true,
988                                                    ExportImportHelperUtil.getAllLayoutIds(
989                                                            group.getGroupId(), true),
990                                                    parameterMap);
991    
992                            ExportImportConfiguration exportImportConfiguration =
993                                    exportImportConfigurationLocalService.
994                                            addDraftExportImportConfiguration(
995                                                    user.getUserId(),
996                                                    ExportImportConfigurationConstants.TYPE_EXPORT_LAYOUT,
997                                                    exportLayoutSettingsMap);
998    
999                            files[0] = exportImportLocalService.exportLayoutsAsFile(
1000                                    exportImportConfiguration);
1001                    }
1002    
1003                    if (userGroup.hasPublicLayouts()) {
1004                            Map<String, Serializable> exportLayoutSettingsMap =
1005                                    ExportImportConfigurationSettingsMapFactory.
1006                                            buildExportLayoutSettingsMap(
1007                                                    user, group.getGroupId(), false,
1008                                                    ExportImportHelperUtil.getAllLayoutIds(
1009                                                            group.getGroupId(), false),
1010                                                    parameterMap);
1011    
1012                            ExportImportConfiguration exportImportConfiguration =
1013                                    exportImportConfigurationLocalService.
1014                                            addDraftExportImportConfiguration(
1015                                                    user.getUserId(),
1016                                                    ExportImportConfigurationConstants.TYPE_EXPORT_LAYOUT,
1017                                                    exportLayoutSettingsMap);
1018    
1019                            files[1] = exportImportLocalService.exportLayoutsAsFile(
1020                                    exportImportConfiguration);
1021                    }
1022    
1023                    return files;
1024            }
1025    
1026            protected Map<String, String[]> getLayoutTemplatesParameters() {
1027                    Map<String, String[]> parameterMap = new LinkedHashMap<>();
1028    
1029                    parameterMap.put(
1030                            PortletDataHandlerKeys.DATA_STRATEGY,
1031                            new String[] {PortletDataHandlerKeys.DATA_STRATEGY_MIRROR});
1032                    parameterMap.put(
1033                            PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
1034                            new String[] {Boolean.FALSE.toString()});
1035                    parameterMap.put(
1036                            PortletDataHandlerKeys.DELETE_PORTLET_DATA,
1037                            new String[] {Boolean.FALSE.toString()});
1038                    parameterMap.put(
1039                            PortletDataHandlerKeys.LAYOUT_SET_SETTINGS,
1040                            new String[] {Boolean.FALSE.toString()});
1041                    parameterMap.put(
1042                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
1043                            new String[] {
1044                                    PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_NAME
1045                            });
1046                    parameterMap.put(
1047                            PortletDataHandlerKeys.LOGO,
1048                            new String[] {Boolean.FALSE.toString()});
1049                    parameterMap.put(
1050                            PortletDataHandlerKeys.PERMISSIONS,
1051                            new String[] {Boolean.TRUE.toString()});
1052                    parameterMap.put(
1053                            PortletDataHandlerKeys.PORTLET_CONFIGURATION,
1054                            new String[] {Boolean.TRUE.toString()});
1055                    parameterMap.put(
1056                            PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL,
1057                            new String[] {Boolean.TRUE.toString()});
1058                    parameterMap.put(
1059                            PortletDataHandlerKeys.PORTLET_DATA,
1060                            new String[] {Boolean.TRUE.toString()});
1061                    parameterMap.put(
1062                            PortletDataHandlerKeys.PORTLET_DATA_ALL,
1063                            new String[] {Boolean.TRUE.toString()});
1064                    parameterMap.put(
1065                            PortletDataHandlerKeys.PORTLET_SETUP_ALL,
1066                            new String[] {Boolean.TRUE.toString()});
1067                    parameterMap.put(
1068                            PortletDataHandlerKeys.PORTLETS_MERGE_MODE,
1069                            new String[] {
1070                                    PortletDataHandlerKeys.PORTLETS_MERGE_MODE_ADD_TO_BOTTOM
1071                            });
1072                    parameterMap.put(
1073                            PortletDataHandlerKeys.THEME_REFERENCE,
1074                            new String[] {Boolean.TRUE.toString()});
1075                    parameterMap.put(
1076                            PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE,
1077                            new String[] {Boolean.FALSE.toString()});
1078                    parameterMap.put(
1079                            PortletDataHandlerKeys.USER_ID_STRATEGY,
1080                            new String[] {UserIdStrategy.CURRENT_USER_ID});
1081    
1082                    return parameterMap;
1083            }
1084    
1085            protected void importLayouts(
1086                            long userId, Map<String, String[]> parameterMap,
1087                            File privateLayoutsFile, File publicLayoutsFile)
1088                    throws PortalException {
1089    
1090                    User user = userPersistence.findByPrimaryKey(userId);
1091    
1092                    long groupId = user.getGroupId();
1093    
1094                    if (privateLayoutsFile != null) {
1095                            Map<String, Serializable> importLayoutSettingsMap =
1096                                    ExportImportConfigurationSettingsMapFactory.
1097                                            buildImportLayoutSettingsMap(
1098                                                    user, groupId, true, null, parameterMap);
1099    
1100                            ExportImportConfiguration exportImportConfiguration =
1101                                    exportImportConfigurationLocalService.
1102                                            addDraftExportImportConfiguration(
1103                                                    user.getUserId(),
1104                                                    ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT,
1105                                                    importLayoutSettingsMap);
1106    
1107                            exportImportLocalService.importLayouts(
1108                                    exportImportConfiguration, privateLayoutsFile);
1109                    }
1110    
1111                    if (publicLayoutsFile != null) {
1112                            Map<String, Serializable> importLayoutSettingsMap =
1113                                    ExportImportConfigurationSettingsMapFactory.
1114                                            buildImportLayoutSettingsMap(
1115                                                    user, groupId, false, null, parameterMap);
1116    
1117                            ExportImportConfiguration exportImportConfiguration =
1118                                    exportImportConfigurationLocalService.
1119                                            addDraftExportImportConfiguration(
1120                                                    user.getUserId(),
1121                                                    ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT,
1122                                                    importLayoutSettingsMap);
1123    
1124                            exportImportLocalService.importLayouts(
1125                                    exportImportConfiguration, publicLayoutsFile);
1126                    }
1127            }
1128    
1129            protected boolean isUseCustomSQL(LinkedHashMap<String, Object> params) {
1130                    if (MapUtil.isEmpty(params)) {
1131                            return false;
1132                    }
1133    
1134                    return true;
1135            }
1136    
1137            protected void validate(long userGroupId, long companyId, String name)
1138                    throws PortalException {
1139    
1140                    if (Validator.isNull(name) || (name.indexOf(CharPool.COMMA) != -1) ||
1141                            (name.indexOf(CharPool.STAR) != -1)) {
1142    
1143                            throw new UserGroupNameException();
1144                    }
1145    
1146                    if (Validator.isNumber(name) &&
1147                            !PropsValues.USER_GROUPS_NAME_ALLOW_NUMERIC) {
1148    
1149                            throw new UserGroupNameException();
1150                    }
1151    
1152                    try {
1153                            UserGroup userGroup = userGroupFinder.findByC_N(companyId, name);
1154    
1155                            if (userGroup.getUserGroupId() != userGroupId) {
1156                                    throw new DuplicateUserGroupException(
1157                                            "{userGroupId=" + userGroupId + "}");
1158                            }
1159                    }
1160                    catch (NoSuchUserGroupException nsuge) {
1161                    }
1162            }
1163    
1164    }