1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.service.impl;
16  
17  import com.liferay.portal.DuplicateGroupException;
18  import com.liferay.portal.GroupFriendlyURLException;
19  import com.liferay.portal.GroupNameException;
20  import com.liferay.portal.NoSuchGroupException;
21  import com.liferay.portal.NoSuchLayoutSetException;
22  import com.liferay.portal.NoSuchRoleException;
23  import com.liferay.portal.RequiredGroupException;
24  import com.liferay.portal.kernel.annotation.Propagation;
25  import com.liferay.portal.kernel.annotation.Transactional;
26  import com.liferay.portal.kernel.dao.orm.QueryUtil;
27  import com.liferay.portal.kernel.exception.PortalException;
28  import com.liferay.portal.kernel.exception.SystemException;
29  import com.liferay.portal.kernel.log.Log;
30  import com.liferay.portal.kernel.log.LogFactoryUtil;
31  import com.liferay.portal.kernel.messaging.DestinationNames;
32  import com.liferay.portal.kernel.scheduler.SchedulerEngineUtil;
33  import com.liferay.portal.kernel.scheduler.messaging.SchedulerRequest;
34  import com.liferay.portal.kernel.util.GetterUtil;
35  import com.liferay.portal.kernel.util.OrderByComparator;
36  import com.liferay.portal.kernel.util.PropsKeys;
37  import com.liferay.portal.kernel.util.StringPool;
38  import com.liferay.portal.kernel.util.StringUtil;
39  import com.liferay.portal.kernel.util.UnicodeProperties;
40  import com.liferay.portal.kernel.util.Validator;
41  import com.liferay.portal.lar.PortletDataHandlerKeys;
42  import com.liferay.portal.model.Company;
43  import com.liferay.portal.model.Group;
44  import com.liferay.portal.model.GroupConstants;
45  import com.liferay.portal.model.Layout;
46  import com.liferay.portal.model.LayoutConstants;
47  import com.liferay.portal.model.LayoutPrototype;
48  import com.liferay.portal.model.LayoutSet;
49  import com.liferay.portal.model.LayoutSetPrototype;
50  import com.liferay.portal.model.LayoutTypePortlet;
51  import com.liferay.portal.model.Organization;
52  import com.liferay.portal.model.Resource;
53  import com.liferay.portal.model.ResourceConstants;
54  import com.liferay.portal.model.Role;
55  import com.liferay.portal.model.RoleConstants;
56  import com.liferay.portal.model.User;
57  import com.liferay.portal.model.UserGroup;
58  import com.liferay.portal.model.impl.LayoutImpl;
59  import com.liferay.portal.security.permission.PermissionCacheUtil;
60  import com.liferay.portal.service.ServiceContext;
61  import com.liferay.portal.service.base.GroupLocalServiceBaseImpl;
62  import com.liferay.portal.util.FriendlyURLNormalizer;
63  import com.liferay.portal.util.PortalUtil;
64  import com.liferay.portal.util.PropsUtil;
65  import com.liferay.portal.util.PropsValues;
66  import com.liferay.portal.util.comparator.GroupNameComparator;
67  import com.liferay.portlet.communities.util.StagingUtil;
68  import com.liferay.util.UniqueList;
69  
70  import java.io.File;
71  
72  import java.util.ArrayList;
73  import java.util.HashMap;
74  import java.util.Iterator;
75  import java.util.LinkedHashMap;
76  import java.util.List;
77  import java.util.Map;
78  
79  /**
80   * <a href="GroupLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
81   *
82   * @author Brian Wing Shun Chan
83   * @author Alexander Chow
84   * @author Bruno Farache
85   * @author Wesley Gong
86   */
87  public class GroupLocalServiceImpl extends GroupLocalServiceBaseImpl {
88  
89      public GroupLocalServiceImpl() {
90          initImportLARFile();
91      }
92  
93      public Group addGroup(
94              long userId, String className, long classPK, String name,
95              String description, int type, String friendlyURL, boolean active,
96              ServiceContext serviceContext)
97          throws PortalException, SystemException {
98  
99          return addGroup(
100             userId, className, classPK, GroupConstants.DEFAULT_LIVE_GROUP_ID,
101             name, description, type, friendlyURL, active, serviceContext);
102     }
103 
104     public Group addGroup(
105             long userId, String className, long classPK, long liveGroupId,
106             String name, String description, int type, String friendlyURL,
107             boolean active, ServiceContext serviceContext)
108         throws PortalException, SystemException {
109 
110         // Group
111 
112         User user = userPersistence.findByPrimaryKey(userId);
113         className = GetterUtil.getString(className);
114         long classNameId = PortalUtil.getClassNameId(className);
115 
116         String friendlyName = name;
117 
118         if (className.equals(Organization.class.getName())) {
119             Organization organization =
120                 organizationPersistence.findByPrimaryKey(classPK);
121 
122             friendlyName = organization.getName();
123         }
124 
125         long groupId = 0;
126 
127         while (true) {
128             groupId = counterLocalService.increment();
129 
130             User userScreenName = userPersistence.fetchByC_SN(
131                 user.getCompanyId(), String.valueOf(groupId));
132 
133             if (userScreenName == null) {
134                 break;
135             }
136         }
137 
138         long groupClassNameId = PortalUtil.getClassNameId(Group.class);
139 
140         if ((classNameId <= 0) || className.equals(Group.class.getName())) {
141             validateName(groupId, user.getCompanyId(), name);
142 
143             classNameId = groupClassNameId;
144             classPK = groupId;
145         }
146         else {
147             name = String.valueOf(classPK);
148         }
149 
150         long parentGroupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
151 
152         if (className.equals(Layout.class.getName())) {
153             Layout layout = layoutLocalService.getLayout(classPK);
154 
155             parentGroupId = layout.getGroupId();
156         }
157 
158         friendlyURL = getFriendlyURL(
159             user.getCompanyId(), groupId, classNameId, classPK, friendlyName,
160             friendlyURL);
161 
162         validateFriendlyURL(
163             user.getCompanyId(), groupId, classNameId, classPK, friendlyURL);
164 
165         Group group = groupPersistence.create(groupId);
166 
167         group.setCompanyId(user.getCompanyId());
168         group.setCreatorUserId(userId);
169         group.setClassNameId(classNameId);
170         group.setClassPK(classPK);
171         group.setParentGroupId(parentGroupId);
172         group.setLiveGroupId(liveGroupId);
173         group.setName(name);
174         group.setDescription(description);
175         group.setType(type);
176         group.setFriendlyURL(friendlyURL);
177         group.setActive(active);
178 
179         groupPersistence.update(group, false);
180 
181         // Layout sets
182 
183         layoutSetLocalService.addLayoutSet(groupId, true);
184 
185         layoutSetLocalService.addLayoutSet(groupId, false);
186 
187         if ((classNameId == groupClassNameId) && !user.isDefaultUser()) {
188 
189             // Resources
190 
191             resourceLocalService.addResources(
192                 group.getCompanyId(), 0, 0, Group.class.getName(),
193                 group.getGroupId(), false, false, false);
194 
195             // Community roles
196 
197             Role role = roleLocalService.getRole(
198                 group.getCompanyId(), RoleConstants.COMMUNITY_OWNER);
199 
200             userGroupRoleLocalService.addUserGroupRoles(
201                 userId, groupId, new long[] {role.getRoleId()});
202 
203             // User
204 
205             userLocalService.addGroupUsers(
206                 group.getGroupId(), new long[] {userId});
207 
208             // Asset
209 
210             if (serviceContext != null) {
211                 updateAsset(
212                     userId, group, serviceContext.getAssetCategoryIds(),
213                     serviceContext.getAssetTagNames());
214             }
215         }
216         else if (className.equals(Organization.class.getName()) &&
217                  !user.isDefaultUser()) {
218 
219             // Resources
220 
221             resourceLocalService.addResources(
222                 group.getCompanyId(), 0, 0, Group.class.getName(),
223                 group.getGroupId(), false, false, false);
224         }
225 
226         return group;
227     }
228 
229     public void addRoleGroups(long roleId, long[] groupIds)
230         throws SystemException {
231 
232         rolePersistence.addGroups(roleId, groupIds);
233 
234         PermissionCacheUtil.clearCache();
235     }
236 
237     public void addUserGroups(long userId, long[] groupIds)
238         throws SystemException {
239 
240         userPersistence.addGroups(userId, groupIds);
241 
242         PermissionCacheUtil.clearCache();
243     }
244 
245     @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
246     public void checkCompanyGroup(long companyId)
247         throws PortalException, SystemException {
248 
249         long classNameId = PortalUtil.getClassNameId(Company.class);
250 
251         int count = groupPersistence.countByC_C_C(
252             companyId, classNameId, companyId);
253 
254         if (count == 0) {
255             long defaultUserId = userLocalService.getDefaultUserId(companyId);
256 
257             groupLocalService.addGroup(
258                 defaultUserId, Company.class.getName(), companyId, null, null,
259                 0, null, true, null);
260         }
261     }
262 
263     @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
264     public void checkSystemGroups(long companyId)
265         throws PortalException, SystemException {
266 
267         for (Group group : groupFinder.findBySystem(companyId)) {
268             _systemGroupsMap.put(companyId + group.getName(), group);
269         }
270 
271         long defaultUserId = userLocalService.getDefaultUserId(companyId);
272 
273         String[] systemGroups = PortalUtil.getSystemGroups();
274 
275         for (String name : systemGroups) {
276             Group group = _systemGroupsMap.get(companyId + name);
277 
278             try {
279                 if (group == null) {
280                     group = groupPersistence.findByC_N(companyId, name);
281                 }
282             }
283             catch (NoSuchGroupException nsge) {
284                 int type = GroupConstants.TYPE_COMMUNITY_OPEN;
285                 String friendlyURL = null;
286 
287                 if (name.equals(GroupConstants.CONTROL_PANEL)) {
288                     type = GroupConstants.TYPE_COMMUNITY_PRIVATE;
289                     friendlyURL = GroupConstants.CONTROL_PANEL_FRIENDLY_URL;
290                 }
291                 else if (name.equals(GroupConstants.GUEST)) {
292                     friendlyURL = "/guest";
293                 }
294 
295                 group = groupLocalService.addGroup(
296                     defaultUserId, null, 0, name, null, type, friendlyURL,
297                     true, null);
298             }
299 
300             if (group.getName().equals(GroupConstants.CONTROL_PANEL)) {
301                 LayoutSet layoutSet = layoutSetLocalService.getLayoutSet(
302                     group.getGroupId(), true);
303 
304                 if (layoutSet.getPageCount() == 0) {
305                     addControlPanelLayouts(group);
306                 }
307             }
308 
309             if (group.getName().equals(GroupConstants.GUEST)) {
310                 LayoutSet layoutSet = layoutSetLocalService.getLayoutSet(
311                     group.getGroupId(), false);
312 
313                 if (layoutSet.getPageCount() == 0) {
314                     addDefaultGuestPublicLayouts(group);
315                 }
316             }
317 
318             _systemGroupsMap.put(companyId + name, group);
319         }
320     }
321 
322     public void deleteGroup(long groupId)
323         throws PortalException, SystemException {
324 
325         Group group = groupPersistence.findByPrimaryKey(groupId);
326 
327         if (PortalUtil.isSystemGroup(group.getName())) {
328             throw new RequiredGroupException(String.valueOf(groupId));
329         }
330 
331         // Layout sets
332 
333         try {
334             layoutSetLocalService.deleteLayoutSet(groupId, true);
335         }
336         catch (NoSuchLayoutSetException nslse) {
337         }
338 
339         try {
340             layoutSetLocalService.deleteLayoutSet(groupId, false);
341         }
342         catch (NoSuchLayoutSetException nslse) {
343         }
344 
345         // Role
346 
347         try {
348             Role role = roleLocalService.getGroupRole(
349                 group.getCompanyId(), groupId);
350 
351             roleLocalService.deleteRole(role.getRoleId());
352         }
353         catch (NoSuchRoleException nsre) {
354         }
355 
356         // Group roles
357 
358         userGroupRoleLocalService.deleteUserGroupRolesByGroupId(groupId);
359 
360         // User group roles
361 
362         userGroupGroupRoleLocalService.deleteUserGroupGroupRolesByGroupId(
363             groupId);
364 
365         // Membership requests
366 
367         membershipRequestLocalService.deleteMembershipRequests(
368             group.getGroupId());
369 
370         // Staging
371 
372         unscheduleStaging(group);
373 
374         if (group.hasStagingGroup()) {
375             deleteGroup(group.getStagingGroup().getGroupId());
376         }
377 
378         // Asset
379 
380         if (group.isCommunity()) {
381             assetEntryLocalService.deleteEntry(Group.class.getName(), groupId);
382         }
383 
384         // Blogs
385 
386         blogsEntryLocalService.deleteEntries(groupId);
387         blogsStatsUserLocalService.deleteStatsUserByGroupId(groupId);
388 
389         // Bookmarks
390 
391         bookmarksFolderLocalService.deleteFolders(groupId);
392 
393         // Calendar
394 
395         calEventLocalService.deleteEvents(groupId);
396 
397         // Document library
398 
399         dlFolderLocalService.deleteFolders(groupId);
400 
401         // Image gallery
402 
403         igFolderLocalService.deleteFolders(groupId);
404 
405         // Journal
406 
407         journalArticleLocalService.deleteArticles(groupId);
408         journalTemplateLocalService.deleteTemplates(groupId);
409         journalStructureLocalService.deleteStructures(groupId);
410 
411         // Message boards
412 
413         mbBanLocalService.deleteBansByGroupId(groupId);
414         mbCategoryLocalService.deleteCategories(groupId);
415         mbStatsUserLocalService.deleteStatsUsersByGroupId(groupId);
416 
417         // Polls
418 
419         pollsQuestionLocalService.deleteQuestions(groupId);
420 
421         // Shopping
422 
423         shoppingCartLocalService.deleteGroupCarts(groupId);
424         shoppingCategoryLocalService.deleteCategories(groupId);
425         shoppingCouponLocalService.deleteCoupons(groupId);
426         shoppingOrderLocalService.deleteOrders(groupId);
427 
428         // Software catalog
429 
430         scFrameworkVersionLocalService.deleteFrameworkVersions(groupId);
431         scProductEntryLocalService.deleteProductEntries(groupId);
432 
433         // Wiki
434 
435         wikiNodeLocalService.deleteNodes(groupId);
436 
437         // Resources
438 
439         Iterator<Resource> itr = resourceFinder.findByC_P(
440             group.getCompanyId(), String.valueOf(groupId)).iterator();
441 
442         while (itr.hasNext()) {
443             Resource resource = itr.next();
444 
445             resourceLocalService.deleteResource(resource);
446         }
447 
448         if (!group.isStagingGroup() &&
449             (group.isCommunity() || group.isOrganization())) {
450 
451             resourceLocalService.deleteResource(
452                 group.getCompanyId(), Group.class.getName(),
453                 ResourceConstants.SCOPE_INDIVIDUAL, group.getGroupId());
454         }
455 
456         // Group
457 
458         groupPersistence.remove(group);
459 
460         // Permission cache
461 
462         PermissionCacheUtil.clearCache();
463     }
464 
465     public Group getCompanyGroup(long companyId)
466         throws PortalException, SystemException {
467 
468         long classNameId = PortalUtil.getClassNameId(Company.class);
469 
470         return groupPersistence.findByC_C_C(companyId, classNameId, companyId);
471     }
472 
473     public List<Group> getCompanyGroups(long companyId, int start, int end)
474         throws SystemException {
475 
476         return groupPersistence.findByCompanyId(companyId, start, end);
477     }
478 
479     public int getCompanyGroupsCount(long companyId) throws SystemException {
480         return groupPersistence.countByCompanyId(companyId);
481     }
482 
483     public Group getFriendlyURLGroup(long companyId, String friendlyURL)
484         throws PortalException, SystemException {
485 
486         if (Validator.isNull(friendlyURL)) {
487             throw new NoSuchGroupException();
488         }
489 
490         friendlyURL = getFriendlyURL(friendlyURL);
491 
492         return groupPersistence.findByC_F(companyId, friendlyURL);
493     }
494 
495     public Group getGroup(long groupId)
496         throws PortalException, SystemException {
497 
498         return groupPersistence.findByPrimaryKey(groupId);
499     }
500 
501     public Group getGroup(long companyId, String name)
502         throws PortalException, SystemException {
503 
504         Group group = _systemGroupsMap.get(companyId + name);
505 
506         if (group != null) {
507             return group;
508         }
509 
510         return groupPersistence.findByC_N(companyId, name);
511     }
512 
513     public List<Group> getGroups(long[] groupIds)
514         throws PortalException, SystemException {
515 
516         List<Group> groups = new ArrayList<Group>(groupIds.length);
517 
518         for (long groupId : groupIds) {
519             Group group = getGroup(groupId);
520 
521             groups.add(group);
522         }
523 
524         return groups;
525     }
526 
527     public Group getLayoutGroup(long companyId, long plid)
528         throws PortalException, SystemException {
529 
530         long classNameId = PortalUtil.getClassNameId(Layout.class);
531 
532         return groupPersistence.findByC_C_C(companyId, classNameId, plid);
533     }
534 
535     public Group getLayoutPrototypeGroup(long companyId, long layoutPrototypeId)
536         throws PortalException, SystemException {
537 
538         long classNameId = PortalUtil.getClassNameId(LayoutPrototype.class);
539 
540         return groupPersistence.findByC_C_C(
541             companyId, classNameId, layoutPrototypeId);
542     }
543 
544     public Group getLayoutSetPrototypeGroup(
545             long companyId, long layoutSetPrototypeId)
546         throws PortalException, SystemException {
547 
548         long classNameId = PortalUtil.getClassNameId(LayoutSetPrototype.class);
549 
550         return groupPersistence.findByC_C_C(
551             companyId, classNameId, layoutSetPrototypeId);
552     }
553 
554     public List<Group> getNoLayoutsGroups(
555             String className, boolean privateLayout, int start, int end)
556         throws SystemException {
557 
558         long classNameId = PortalUtil.getClassNameId(className);
559 
560         return groupFinder.findByNoLayouts(
561             classNameId, privateLayout, start, end);
562     }
563 
564     public List<Group> getNullFriendlyURLGroups() throws SystemException {
565         return groupFinder.findByNullFriendlyURL();
566     }
567 
568     public Group getOrganizationGroup(long companyId, long organizationId)
569         throws PortalException, SystemException {
570 
571         long classNameId = PortalUtil.getClassNameId(Organization.class);
572 
573         return groupPersistence.findByC_C_C(
574             companyId, classNameId, organizationId);
575     }
576 
577     public List<Group> getOrganizationsGroups(
578         List<Organization> organizations) {
579 
580         List<Group> organizationGroups = new ArrayList<Group>();
581 
582         for (int i = 0; i < organizations.size(); i++) {
583             Organization organization = organizations.get(i);
584 
585             Group group = organization.getGroup();
586 
587             organizationGroups.add(group);
588         }
589 
590         return organizationGroups;
591     }
592 
593     public List<Group> getRoleGroups(long roleId) throws SystemException {
594         return rolePersistence.getGroups(roleId);
595     }
596 
597     public Group getStagingGroup(long liveGroupId)
598         throws PortalException, SystemException {
599 
600         return groupPersistence.findByLiveGroupId(liveGroupId);
601     }
602 
603     public Group getUserGroup(long companyId, long userId)
604         throws PortalException, SystemException {
605 
606         long classNameId = PortalUtil.getClassNameId(User.class);
607 
608         return groupPersistence.findByC_C_C(companyId, classNameId, userId);
609     }
610 
611     public Group getUserGroupGroup(long companyId, long userGroupId)
612         throws PortalException, SystemException {
613 
614         long classNameId = PortalUtil.getClassNameId(UserGroup.class);
615 
616         return groupPersistence.findByC_C_C(
617             companyId, classNameId, userGroupId);
618     }
619 
620     public List<Group> getUserGroups(long userId)
621         throws PortalException, SystemException {
622 
623         return getUserGroups(userId, false);
624     }
625 
626     public List<Group> getUserGroups(long userId, boolean inherit)
627         throws PortalException, SystemException {
628 
629         return getUserGroups(
630             userId, inherit, QueryUtil.ALL_POS, QueryUtil.ALL_POS);
631     }
632 
633     public List<Group> getUserGroups(long userId, int start, int end)
634         throws PortalException, SystemException {
635 
636         return getUserGroups(userId, false, start, end);
637     }
638 
639     public List<Group> getUserGroups(
640             long userId, boolean inherit, int start, int end)
641         throws PortalException, SystemException {
642 
643         if (inherit) {
644             User user = userPersistence.findByPrimaryKey(userId);
645 
646             LinkedHashMap<String, Object> groupParams =
647                 new LinkedHashMap<String, Object>();
648 
649             groupParams.put("usersGroups", new Long(userId));
650 
651             return search(
652                 user.getCompanyId(), null, null, groupParams, start, end);
653         }
654         else {
655             return userPersistence.getGroups(userId);
656         }
657     }
658 
659     public List<Group> getUserGroupsGroups(List<UserGroup> userGroups) {
660         List<Group> userGroupGroups = new ArrayList<Group>();
661 
662         for (int i = 0; i < userGroups.size(); i++) {
663             UserGroup userGroup = userGroups.get(i);
664 
665             Group group = userGroup.getGroup();
666 
667             userGroupGroups.add(group);
668         }
669 
670         return userGroupGroups;
671     }
672 
673     public List<Group> getUserOrganizationsGroups(
674             long userId, int start, int end)
675         throws PortalException, SystemException {
676 
677         List<Group> userOrgsGroups = new UniqueList<Group>();
678 
679         List<Organization> userOrgs =
680             organizationLocalService.getUserOrganizations(
681                 userId, true, start, end);
682 
683         for (Organization organization : userOrgs) {
684             userOrgsGroups.add(0, organization.getGroup());
685 
686             if (!PropsValues.ORGANIZATIONS_MEMBERSHIP_STRICT) {
687                 for (Organization ancestorOrganization :
688                         organization.getAncestors()) {
689 
690                     userOrgsGroups.add(0, ancestorOrganization.getGroup());
691                 }
692             }
693         }
694 
695         return userOrgsGroups;
696     }
697 
698     public boolean hasRoleGroup(long roleId, long groupId)
699         throws SystemException {
700 
701         return rolePersistence.containsGroup(roleId, groupId);
702     }
703 
704     public boolean hasStagingGroup(long liveGroupId) throws SystemException {
705         if (groupPersistence.fetchByLiveGroupId(liveGroupId) != null) {
706             return true;
707         }
708         else {
709             return false;
710         }
711     }
712 
713     public boolean hasUserGroup(long userId, long groupId)
714         throws SystemException {
715 
716         if (groupFinder.countByG_U(groupId, userId) > 0) {
717             return true;
718         }
719         else {
720             return false;
721         }
722     }
723 
724     public List<Group> search(
725             long companyId, String name, String description,
726             LinkedHashMap<String, Object> params, int start, int end)
727         throws SystemException {
728 
729         return search(companyId, name, description, params, start, end, null);
730     }
731 
732     public List<Group> search(
733             long companyId, String name, String description,
734             LinkedHashMap<String, Object> params, int start, int end,
735             OrderByComparator obc)
736         throws SystemException {
737 
738         if (obc == null) {
739             obc = new GroupNameComparator(true);
740         }
741 
742         return groupFinder.findByC_N_D(
743             companyId, name, description, params, start, end, obc);
744     }
745 
746     public int searchCount(
747             long companyId, String name, String description,
748             LinkedHashMap<String, Object> params)
749         throws SystemException {
750 
751         return groupFinder.countByC_N_D(companyId, name, description, params);
752     }
753 
754     public void setRoleGroups(long roleId, long[] groupIds)
755         throws SystemException {
756 
757         rolePersistence.setGroups(roleId, groupIds);
758 
759         PermissionCacheUtil.clearCache();
760     }
761 
762     public void unsetRoleGroups(long roleId, long[] groupIds)
763         throws SystemException {
764 
765         rolePersistence.removeGroups(roleId, groupIds);
766 
767         PermissionCacheUtil.clearCache();
768     }
769 
770     public void unsetUserGroups(long userId, long[] groupIds)
771         throws SystemException {
772 
773         userGroupRoleLocalService.deleteUserGroupRoles(userId, groupIds);
774 
775         userPersistence.removeGroups(userId, groupIds);
776 
777         PermissionCacheUtil.clearCache();
778     }
779 
780     public void updateAsset(
781             long userId, Group group, long[] assetCategoryIds,
782             String[] assetTagNames)
783         throws PortalException, SystemException {
784 
785         User user = userPersistence.findByPrimaryKey(userId);
786 
787         Company company = companyPersistence.findByPrimaryKey(
788             user.getCompanyId());
789 
790         Group companyGroup = company.getGroup();
791 
792         assetEntryLocalService.updateEntry(
793             userId, companyGroup.getGroupId(), Group.class.getName(),
794             group.getGroupId(), assetCategoryIds, assetTagNames, false, null,
795             null, null, null, null, group.getDescriptiveName(),
796             group.getDescription(), null, null, 0, 0, null, false);
797     }
798 
799     public Group updateFriendlyURL(long groupId, String friendlyURL)
800         throws PortalException, SystemException {
801 
802         Group group = groupPersistence.findByPrimaryKey(groupId);
803 
804         if (group.isUser()) {
805             User user = userPersistence.findByPrimaryKey(group.getClassPK());
806 
807             friendlyURL = StringPool.SLASH + user.getScreenName();
808 
809             if (group.getFriendlyURL().equals(friendlyURL)) {
810                 return group;
811             }
812         }
813 
814         friendlyURL = getFriendlyURL(
815             group.getCompanyId(), groupId, group.getClassNameId(),
816             group.getClassPK(), StringPool.BLANK, friendlyURL);
817 
818         validateFriendlyURL(
819             group.getCompanyId(), group.getGroupId(), group.getClassNameId(),
820             group.getClassPK(), friendlyURL);
821 
822         group.setFriendlyURL(friendlyURL);
823 
824         groupPersistence.update(group, false);
825 
826         return group;
827     }
828 
829     public Group updateGroup(
830             long groupId, String name, String description, int type,
831             String friendlyURL, boolean active, ServiceContext serviceContext)
832         throws PortalException, SystemException {
833 
834         Group group = groupPersistence.findByPrimaryKey(groupId);
835 
836         String className = group.getClassName();
837         long classNameId = group.getClassNameId();
838         long classPK = group.getClassPK();
839         friendlyURL = getFriendlyURL(
840             group.getCompanyId(), groupId, classNameId, classPK,
841             StringPool.BLANK, friendlyURL);
842 
843         if ((classNameId <= 0) || className.equals(Group.class.getName())) {
844             validateName(group.getGroupId(), group.getCompanyId(), name);
845         }
846         else {
847             name = String.valueOf(classPK);
848         }
849 
850         if (PortalUtil.isSystemGroup(group.getName()) &&
851             !group.getName().equals(name)) {
852 
853             throw new RequiredGroupException();
854         }
855 
856         validateFriendlyURL(
857             group.getCompanyId(), group.getGroupId(), group.getClassNameId(),
858             group.getClassPK(), friendlyURL);
859 
860         group.setName(name);
861         group.setDescription(description);
862         group.setType(type);
863         group.setFriendlyURL(friendlyURL);
864         group.setActive(active);
865 
866         groupPersistence.update(group, false);
867 
868         // Asset
869 
870         if ((serviceContext != null) && group.isCommunity()) {
871             updateAsset(
872                 group.getCreatorUserId(), group,
873                 serviceContext.getAssetCategoryIds(),
874                 serviceContext.getAssetTagNames());
875         }
876 
877         return group;
878     }
879 
880     public Group updateGroup(long groupId, String typeSettings)
881         throws PortalException, SystemException {
882 
883         Group group = groupPersistence.findByPrimaryKey(groupId);
884 
885         group.setTypeSettings(typeSettings);
886 
887         groupPersistence.update(group, false);
888 
889         return group;
890     }
891 
892     public Group updateWorkflow(
893             long groupId, boolean workflowEnabled, int workflowStages,
894             String workflowRoleNames)
895         throws PortalException, SystemException {
896 
897         Group group = groupPersistence.findByPrimaryKey(groupId);
898 
899         UnicodeProperties props = group.getTypeSettingsProperties();
900 
901         props.setProperty("workflowEnabled", String.valueOf(workflowEnabled));
902 
903         if (workflowEnabled) {
904             if (workflowStages < PropsValues.TASKS_DEFAULT_STAGES) {
905                 workflowStages = PropsValues.TASKS_DEFAULT_STAGES;
906             }
907 
908             if (Validator.isNull(workflowRoleNames)) {
909                 workflowRoleNames = PropsValues.TASKS_DEFAULT_ROLE_NAMES;
910             }
911 
912             props.setProperty("workflowStages", String.valueOf(workflowStages));
913             props.setProperty("workflowRoleNames", workflowRoleNames);
914         }
915 
916         group.setTypeSettings(group.getTypeSettings());
917 
918         groupPersistence.update(group, false);
919 
920         if (!workflowEnabled) {
921             tasksProposalLocalService.deleteProposals(groupId);
922         }
923 
924         return group;
925     }
926 
927     protected void addControlPanelLayouts(Group group)
928         throws PortalException, SystemException {
929 
930         long defaultUserId = userLocalService.getDefaultUserId(
931             group.getCompanyId());
932 
933         String friendlyURL = getFriendlyURL(
934             PropsValues.CONTROL_PANEL_LAYOUT_FRIENDLY_URL);
935 
936         ServiceContext serviceContext = new ServiceContext();
937 
938         layoutLocalService.addLayout(
939             defaultUserId, group.getGroupId(), true,
940             LayoutConstants.DEFAULT_PARENT_LAYOUT_ID,
941             PropsValues.CONTROL_PANEL_LAYOUT_NAME, StringPool.BLANK,
942             StringPool.BLANK, LayoutConstants.TYPE_CONTROL_PANEL, false,
943             friendlyURL, serviceContext);
944     }
945 
946     protected void addDefaultGuestPublicLayoutByProperties(Group group)
947         throws PortalException, SystemException {
948 
949         long defaultUserId = userLocalService.getDefaultUserId(
950             group.getCompanyId());
951         String friendlyURL = getFriendlyURL(
952             PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_FRIENDLY_URL);
953 
954         ServiceContext serviceContext = new ServiceContext();
955 
956         Layout layout = layoutLocalService.addLayout(
957             defaultUserId, group.getGroupId(), false,
958             LayoutConstants.DEFAULT_PARENT_LAYOUT_ID,
959             PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_NAME, StringPool.BLANK,
960             StringPool.BLANK, LayoutConstants.TYPE_PORTLET, false, friendlyURL,
961             serviceContext);
962 
963         LayoutTypePortlet layoutTypePortlet =
964             (LayoutTypePortlet)layout.getLayoutType();
965 
966         layoutTypePortlet.setLayoutTemplateId(
967             0, PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_TEMPLATE_ID, false);
968 
969         for (int i = 0; i < 10; i++) {
970             String columnId = "column-" + i;
971             String portletIds = PropsUtil.get(
972                 PropsKeys.DEFAULT_GUEST_PUBLIC_LAYOUT_COLUMN + i);
973 
974             layoutTypePortlet.addPortletIds(
975                 0, StringUtil.split(portletIds), columnId, false);
976         }
977 
978         layoutLocalService.updateLayout(
979             layout.getGroupId(), layout.isPrivateLayout(), layout.getLayoutId(),
980             layout.getTypeSettings());
981 
982         boolean updateLayoutSet = false;
983 
984         LayoutSet layoutSet = layout.getLayoutSet();
985 
986         if (Validator.isNotNull(
987                 PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_REGULAR_THEME_ID)) {
988 
989             layoutSet.setThemeId(
990                 PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_REGULAR_THEME_ID);
991 
992             updateLayoutSet = true;
993         }
994 
995         if (Validator.isNotNull(
996                 PropsValues.
997                     DEFAULT_GUEST_PUBLIC_LAYOUT_REGULAR_COLOR_SCHEME_ID)) {
998 
999             layoutSet.setColorSchemeId(
1000                PropsValues.
1001                    DEFAULT_GUEST_PUBLIC_LAYOUT_REGULAR_COLOR_SCHEME_ID);
1002
1003            updateLayoutSet = true;
1004        }
1005
1006        if (Validator.isNotNull(
1007                PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_WAP_THEME_ID)) {
1008
1009            layoutSet.setWapThemeId(
1010                PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_WAP_THEME_ID);
1011
1012            updateLayoutSet = true;
1013        }
1014
1015        if (Validator.isNotNull(
1016                PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_WAP_COLOR_SCHEME_ID)) {
1017
1018            layoutSet.setWapColorSchemeId(
1019                PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUT_WAP_COLOR_SCHEME_ID);
1020
1021            updateLayoutSet = true;
1022        }
1023
1024        if (updateLayoutSet) {
1025            layoutSetLocalService.updateLayoutSet(layoutSet);
1026        }
1027    }
1028
1029    protected void addDefaultGuestPublicLayouts(Group group)
1030        throws PortalException, SystemException {
1031
1032        if (publicLARFile != null) {
1033            addDefaultGuestPublicLayoutsByLAR(group, publicLARFile);
1034        }
1035        else {
1036            addDefaultGuestPublicLayoutByProperties(group);
1037        }
1038    }
1039
1040    protected void addDefaultGuestPublicLayoutsByLAR(Group group, File larFile)
1041        throws PortalException, SystemException {
1042
1043        long defaultUserId = userLocalService.getDefaultUserId(
1044            group.getCompanyId());
1045
1046        Map<String, String[]> parameterMap = new HashMap<String, String[]>();
1047
1048        parameterMap.put(
1049            PortletDataHandlerKeys.CATEGORIES,
1050            new String[] {Boolean.TRUE.toString()});
1051        parameterMap.put(
1052            PortletDataHandlerKeys.PERMISSIONS,
1053            new String[] {Boolean.TRUE.toString()});
1054        parameterMap.put(
1055            PortletDataHandlerKeys.PORTLET_DATA,
1056            new String[] {Boolean.TRUE.toString()});
1057        parameterMap.put(
1058            PortletDataHandlerKeys.PORTLET_DATA_CONTROL_DEFAULT,
1059            new String[] {Boolean.TRUE.toString()});
1060        parameterMap.put(
1061            PortletDataHandlerKeys.PORTLET_SETUP,
1062            new String[] {Boolean.TRUE.toString()});
1063        parameterMap.put(
1064            PortletDataHandlerKeys.USER_PERMISSIONS,
1065            new String[] {Boolean.FALSE.toString()});
1066
1067        layoutLocalService.importLayouts(
1068            defaultUserId, group.getGroupId(), false, parameterMap, larFile);
1069    }
1070
1071    protected String getFriendlyURL(String friendlyURL) {
1072        return FriendlyURLNormalizer.normalize(friendlyURL);
1073    }
1074
1075    protected String getFriendlyURL(
1076            long companyId, long groupId, long classNameId, long classPK,
1077            String friendlyName, String friendlyURL)
1078        throws PortalException, SystemException {
1079
1080        friendlyURL = getFriendlyURL(friendlyURL);
1081
1082        if (Validator.isNull(friendlyURL)) {
1083            friendlyURL = StringPool.SLASH + getFriendlyURL(friendlyName);
1084
1085            String originalFriendlyURL = friendlyURL;
1086
1087            for (int i = 1;; i++) {
1088                try {
1089                    validateFriendlyURL(
1090                        companyId, groupId, classNameId, classPK, friendlyURL);
1091
1092                    break;
1093                }
1094                catch (GroupFriendlyURLException gfurle) {
1095                    int type = gfurle.getType();
1096
1097                    if (type == GroupFriendlyURLException.DUPLICATE) {
1098                        friendlyURL = originalFriendlyURL + i;
1099                    }
1100                    else {
1101                        friendlyURL = StringPool.SLASH + classPK;
1102
1103                        break;
1104                    }
1105                }
1106            }
1107        }
1108
1109        return friendlyURL;
1110    }
1111
1112    protected void initImportLARFile() {
1113        String publicLARFileName = PropsValues.DEFAULT_GUEST_PUBLIC_LAYOUTS_LAR;
1114
1115        if (_log.isDebugEnabled()) {
1116            _log.debug("Reading public LAR file " + publicLARFileName);
1117        }
1118
1119        if (Validator.isNotNull(publicLARFileName)) {
1120            publicLARFile = new File(publicLARFileName);
1121
1122            if (!publicLARFile.exists()) {
1123                _log.error(
1124                    "Public LAR file " + publicLARFile + " does not exist");
1125
1126                publicLARFile = null;
1127            }
1128            else {
1129                if (_log.isDebugEnabled()) {
1130                    _log.debug("Using public LAR file " + publicLARFileName);
1131                }
1132            }
1133        }
1134    }
1135
1136    protected void unscheduleStaging(Group group) {
1137        try {
1138
1139            // Remote publishing
1140
1141            String groupName = StagingUtil.getSchedulerGroupName(
1142                DestinationNames.LAYOUTS_REMOTE_PUBLISHER, group.getGroupId());
1143
1144            List<SchedulerRequest> schedulerRequests =
1145                SchedulerEngineUtil.getScheduledJobs(groupName);
1146
1147            for (SchedulerRequest schedulerRequest : schedulerRequests) {
1148                SchedulerEngineUtil.unschedule(schedulerRequest.getTrigger());
1149            }
1150
1151            long liveGroupId = 0;
1152            long stagingGroupId = 0;
1153
1154            if (group.isStagingGroup()) {
1155                liveGroupId = group.getLiveGroupId();
1156
1157                stagingGroupId = group.getGroupId();
1158            }
1159            else if (group.hasStagingGroup()) {
1160                liveGroupId = group.getGroupId();
1161
1162                stagingGroupId = group.getStagingGroup().getGroupId();
1163            }
1164
1165            if ((liveGroupId != 0) && (stagingGroupId != 0)) {
1166
1167                // Publish to live
1168
1169                groupName = StagingUtil.getSchedulerGroupName(
1170                    DestinationNames.LAYOUTS_LOCAL_PUBLISHER, liveGroupId);
1171
1172                schedulerRequests = SchedulerEngineUtil.getScheduledJobs(
1173                    groupName);
1174
1175                for (SchedulerRequest schedulerRequest : schedulerRequests) {
1176                    SchedulerEngineUtil.unschedule(
1177                        schedulerRequest.getTrigger());
1178                }
1179
1180                // Copy from live
1181
1182                groupName = StagingUtil.getSchedulerGroupName(
1183                    DestinationNames.LAYOUTS_LOCAL_PUBLISHER, stagingGroupId);
1184
1185                schedulerRequests = SchedulerEngineUtil.getScheduledJobs(
1186                    groupName);
1187
1188                for (SchedulerRequest schedulerRequest : schedulerRequests) {
1189                    SchedulerEngineUtil.unschedule(
1190                        schedulerRequest.getTrigger());
1191                }
1192            }
1193        }
1194        catch (Exception e) {
1195            _log.error(
1196                "Unable to unschedule events for group: " + group.getGroupId());
1197        }
1198    }
1199
1200    protected void validateFriendlyURL(
1201            long companyId, long groupId, long classNameId, long classPK,
1202            String friendlyURL)
1203        throws PortalException, SystemException {
1204
1205        Company company = companyPersistence.findByPrimaryKey(companyId);
1206
1207        if (company.isSystem()) {
1208            return;
1209        }
1210
1211        if (Validator.isNull(friendlyURL)) {
1212            return;
1213        }
1214
1215        int exceptionType = LayoutImpl.validateFriendlyURL(friendlyURL);
1216
1217        if (exceptionType != -1) {
1218            throw new GroupFriendlyURLException(exceptionType);
1219        }
1220
1221        Group group = groupPersistence.fetchByC_F(companyId, friendlyURL);
1222
1223        if ((group != null) && (group.getGroupId() != groupId)) {
1224            throw new GroupFriendlyURLException(
1225                GroupFriendlyURLException.DUPLICATE);
1226        }
1227
1228        String groupIdFriendlyURL = friendlyURL.substring(1);
1229
1230        if (Validator.isNumber(groupIdFriendlyURL)) {
1231            long groupClassNameId = PortalUtil.getClassNameId(Group.class);
1232
1233            if (((classNameId != groupClassNameId) &&
1234                 (!groupIdFriendlyURL.equals(String.valueOf(classPK))) &&
1235                 (!PropsValues.USERS_SCREEN_NAME_ALLOW_NUMERIC)) ||
1236                ((classNameId == groupClassNameId) &&
1237                 (!groupIdFriendlyURL.equals(String.valueOf(groupId))))) {
1238
1239                GroupFriendlyURLException gfurle =
1240                    new GroupFriendlyURLException(
1241                        GroupFriendlyURLException.POSSIBLE_DUPLICATE);
1242
1243                gfurle.setKeywordConflict(groupIdFriendlyURL);
1244
1245                throw gfurle;
1246            }
1247        }
1248
1249        String screenName = friendlyURL.substring(1);
1250
1251        User user = userPersistence.fetchByC_SN(companyId, screenName);
1252
1253        if (user != null) {
1254            long userClassNameId = PortalUtil.getClassNameId(User.class);
1255
1256            if ((classNameId == userClassNameId) &&
1257                (classPK == user.getUserId())) {
1258            }
1259            else {
1260                throw new GroupFriendlyURLException(
1261                    GroupFriendlyURLException.DUPLICATE);
1262            }
1263        }
1264
1265        if (StringUtil.count(friendlyURL, StringPool.SLASH) > 1) {
1266            throw new GroupFriendlyURLException(
1267                GroupFriendlyURLException.TOO_DEEP);
1268        }
1269    }
1270
1271    protected void validateName(long groupId, long companyId, String name)
1272        throws PortalException, SystemException {
1273
1274        if ((Validator.isNull(name)) || (Validator.isNumber(name)) ||
1275            (name.indexOf(StringPool.COMMA) != -1) ||
1276            (name.indexOf(StringPool.STAR) != -1)) {
1277
1278            throw new GroupNameException();
1279        }
1280
1281        try {
1282            Group group = groupFinder.findByC_N(companyId, name);
1283
1284            if ((groupId <= 0) || (group.getGroupId() != groupId)) {
1285                throw new DuplicateGroupException();
1286            }
1287        }
1288        catch (NoSuchGroupException nsge) {
1289        }
1290    }
1291
1292    protected File publicLARFile;
1293
1294    private static Log _log = LogFactoryUtil.getLog(
1295        GroupLocalServiceImpl.class);
1296
1297    private Map<String, Group> _systemGroupsMap = new HashMap<String, Group>();
1298
1299}