View Javadoc
1   /*
2    * Copyright (C) 2003-2007 eXo Platform SAS.
3    *
4    * This program is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Affero General Public License
6    * as published by the Free Software Foundation; either version 3
7    * of the License, or (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program; if not, see<http://www.gnu.org/licenses/>.
16   */
17  package org.exoplatform.social.core.space.impl;
18  
19  import java.io.InputStream;
20  import java.util.*;
21  
22  import org.apache.commons.lang.ArrayUtils;
23  import org.apache.commons.lang.StringUtils;
24  
25  import org.exoplatform.commons.api.notification.model.NotificationInfo;
26  import org.exoplatform.commons.api.notification.model.PluginKey;
27  import org.exoplatform.commons.api.notification.model.WebNotificationFilter;
28  import org.exoplatform.commons.api.notification.service.WebNotificationService;
29  import org.exoplatform.commons.utils.ListAccess;
30  import org.exoplatform.container.ExoContainer;
31  import org.exoplatform.container.ExoContainerContext;
32  import org.exoplatform.container.configuration.ConfigurationManager;
33  import org.exoplatform.portal.config.UserACL;
34  import org.exoplatform.services.log.ExoLogger;
35  import org.exoplatform.services.log.Log;
36  import org.exoplatform.services.organization.*;
37  import org.exoplatform.services.security.IdentityConstants;
38  import org.exoplatform.services.security.IdentityRegistry;
39  import org.exoplatform.services.security.MembershipEntry;
40  import org.exoplatform.social.core.application.PortletPreferenceRequiredPlugin;
41  import org.exoplatform.social.core.identity.model.Identity;
42  import org.exoplatform.social.core.identity.model.Profile;
43  import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider;
44  import org.exoplatform.social.core.identity.provider.SpaceIdentityProvider;
45  import org.exoplatform.social.core.model.BannerAttachment;
46  import org.exoplatform.social.core.space.*;
47  import org.exoplatform.social.core.space.model.Space;
48  import org.exoplatform.social.core.space.model.Space.UpdatedField;
49  import org.exoplatform.social.core.space.spi.SpaceApplicationHandler;
50  import org.exoplatform.social.core.space.spi.SpaceLifeCycleListener;
51  import org.exoplatform.social.core.space.spi.SpaceService;
52  import org.exoplatform.social.core.space.spi.SpaceTemplateService;
53  import org.exoplatform.social.core.storage.api.IdentityStorage;
54  import org.exoplatform.social.core.storage.api.SpaceStorage;
55  
56  /**
57   * {@link org.exoplatform.social.core.space.spi.SpaceService} implementation.
58   * @author <a href="mailto:tungcnw@gmail.com">dang.tung</a>
59   * @since  August 29, 2008
60   */
61  public class SpaceServiceImpl implements SpaceService {
62  
63    private static final Log                     LOG                   = ExoLogger.getLogger(SpaceServiceImpl.class.getName());
64  
65    public static final String                   MEMBER                   = "member";
66  
67    public static final String                   MANAGER                  = "manager";
68  
69    private IdentityRegistry                     identityRegistry;
70  
71    private SpaceStorage                         spaceStorage;
72  
73    private IdentityStorage                      identityStorage;
74  
75    private OrganizationService                  orgService               = null;
76  
77    private UserACL                              userACL                  = null;
78  
79    private SpaceLifecycle                       spaceLifeCycle           = new SpaceLifecycle();
80  
81    List<String>                                 portletPrefsRequired = null;
82  
83    /** The offset for list access loading. */
84    private static final int                   OFFSET = 0;
85  
86    /** The limit for list access loading. */
87    private static final int                   LIMIT = 200;
88  
89    private WebNotificationService webNotificationService;
90  
91    private SpacesAdministrationService spacesAdministrationService;
92  
93    private SpaceTemplateService spaceTemplateService;
94  
95    private ConfigurationManager configurationManager;
96  
97    /**
98     * SpaceServiceImpl constructor Initialize
99     * <tt>org.exoplatform.social.space.impl.JCRStorage</tt>
100    *
101    * @throws Exception
102    */
103   public SpaceServiceImpl(SpaceStorage spaceStorage, IdentityStorage identityStorage, UserACL userACL, ConfigurationManager configurationManager,
104                           IdentityRegistry identityRegistry, WebNotificationService webNotificationService,
105                           SpacesAdministrationService spacesAdministrationService, SpaceTemplateService spaceTemplateService) throws Exception {
106     this.spaceStorage = spaceStorage;
107     this.identityStorage = identityStorage;
108     this.identityRegistry = identityRegistry;
109     this.userACL = userACL;
110     this.webNotificationService = webNotificationService;
111     this.spacesAdministrationService = spacesAdministrationService;
112     this.spaceTemplateService = spaceTemplateService;
113     this.configurationManager = configurationManager;
114   }
115 
116   /**
117    * {@inheritDoc}
118    */
119   public List<Space> getAllSpaces() throws SpaceException {
120     try {
121       return Arrays.asList(this.getAllSpacesWithListAccess().load(OFFSET, LIMIT));
122     } catch (Exception e) {
123       throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
124     }
125   }
126 
127   /**
128    * {@inheritDoc}
129    */
130   public ListAccess<Space> getAllSpacesWithListAccess() {
131     return new SpaceListAccess(this.spaceStorage, SpaceListAccess.Type.ALL);
132   }
133 
134   /**
135    * {@inheritDoc}
136    */
137   public Space getSpaceByDisplayName(String spaceDisplayName) {
138     return spaceStorage.getSpaceByDisplayName(spaceDisplayName);
139   }
140 
141   /**
142    * {@inheritDoc}
143    */
144   public Space getSpaceByName(String spaceName) {
145     return getSpaceByPrettyName(spaceName);
146   }
147 
148   /**
149    * {@inheritDoc}
150    */
151   public Space getSpaceByPrettyName(String spacePrettyName) {
152     return spaceStorage.getSpaceByPrettyName(spacePrettyName);
153   }
154 
155   /**
156    * {@inheritDoc}
157    */
158   public List<Space> getSpacesByFirstCharacterOfName(String firstCharacterOfName) throws SpaceException {
159     try {
160       return Arrays.asList(this.getAllSpacesByFilter(new SpaceFilter(firstCharacterOfName.charAt(0))).load(OFFSET, LIMIT));
161     } catch (Exception e) {
162       throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
163     }
164   }
165 
166   /**
167    * {@inheritDoc}
168    */
169   public List<Space> getSpacesBySearchCondition(String searchCondition) throws SpaceException {
170     try {
171       return Arrays.asList(this.getAllSpacesByFilter(new SpaceFilter(searchCondition)).load(OFFSET, LIMIT));
172     } catch (Exception e) {
173       throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
174     }
175   }
176 
177   /**
178    * {@inheritDoc}
179    */
180   public Space getSpaceByGroupId(String groupId) {
181     return spaceStorage.getSpaceByGroupId(groupId);
182   }
183 
184   /**
185    * {@inheritDoc}
186    */
187   public Space getSpaceById(String id) {
188     return spaceStorage.getSpaceById(id);
189   }
190 
191   /**
192    * {@inheritDoc}
193    */
194   public Space getSpaceByUrl(String url) {
195     return spaceStorage.getSpaceByUrl(url);
196   }
197 
198   /**
199    * {@inheritDoc}
200    */
201   public List<Space> getSpaces(String userId) throws SpaceException {
202     try {
203       return Arrays.asList(this.getMemberSpaces(userId).load(OFFSET, LIMIT));
204     } catch (Exception e) {
205       throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
206     }
207   }
208 
209   /**
210    * {@inheritDoc}
211    */
212   public List<Space> getAccessibleSpaces(String userId) throws SpaceException {
213     try {
214       return Arrays.asList(this.getAccessibleSpacesWithListAccess(userId).load(OFFSET, LIMIT));
215     } catch (Exception e) {
216       throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
217     }
218   }
219 
220   /**
221    * {@inheritDoc}
222    */
223   public SpaceListAccess getAccessibleSpacesWithListAccess(String userId) {
224     return new SpaceListAccess(this.spaceStorage, userId, SpaceListAccess.Type.ACCESSIBLE);
225   }
226 
227   /**
228    * {@inheritDoc}
229    */
230   public List<Space> getVisibleSpaces(String userId, SpaceFilter spaceFilter) throws SpaceException {
231     try {
232       return Arrays.asList(this.getVisibleSpacesWithListAccess(userId, spaceFilter).load(OFFSET, LIMIT));
233     } catch (Exception e) {
234       throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
235     }
236   }
237 
238   /**
239    * {@inheritDoc}
240    */
241   public SpaceListAccess getVisibleSpacesWithListAccess(String userId, SpaceFilter spaceFilter) {
242     if (isSuperManager(userId)) {
243       if (spaceFilter == null)
244         return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.ALL);
245       else
246         return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.ALL_FILTER);
247     } else {
248       return new SpaceListAccess(this.spaceStorage, userId, spaceFilter,SpaceListAccess.Type.VISIBLE);
249     }
250   }
251 
252   /**
253    * {@inheritDoc}
254    */
255   public SpaceListAccess getUnifiedSearchSpacesWithListAccess(String userId, SpaceFilter spaceFilter) {
256     return new SpaceListAccess(this.spaceStorage, userId, spaceFilter,SpaceListAccess.Type.UNIFIED_SEARCH);
257   }
258 
259   /**
260    * {@inheritDoc}
261    */
262   public List<Space> getEditableSpaces(String userId)  throws SpaceException {
263     try {
264       return Arrays.asList(this.getSettingableSpaces(userId).load(OFFSET, LIMIT));
265     } catch (Exception e) {
266       throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
267     }
268   }
269 
270   /**
271    * {@inheritDoc}
272    */
273   public List<Space> getInvitedSpaces(String userId) throws SpaceException {
274     try {
275       return Arrays.asList(this.getInvitedSpacesWithListAccess(userId).load(OFFSET, LIMIT));
276     } catch (Exception e) {
277       throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
278     }
279   }
280 
281   /**
282    * {@inheritDoc}
283    */
284   public List<Space> getPublicSpaces(String userId) throws SpaceException {
285     try {
286       return Arrays.asList(this.getPublicSpacesWithListAccess(userId).load(OFFSET, LIMIT));
287     } catch (Exception e) {
288       throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
289     }
290   }
291 
292   /**
293    * {@inheritDoc}
294    */
295   public SpaceListAccess getPublicSpacesWithListAccess(String userId) {
296     if (isSuperManager(userId)) {
297       return new SpaceListAccess(this.spaceStorage, SpaceListAccess.Type.PUBLIC_SUPER_USER);
298     } else {
299       return new SpaceListAccess(this.spaceStorage, userId, SpaceListAccess.Type.PUBLIC);
300     }
301   }
302 
303   /**
304    * {@inheritDoc}
305    */
306   public List<Space> getPendingSpaces(String userId) throws SpaceException {
307     try {
308       return Arrays.asList(this.getPendingSpacesWithListAccess(userId).load(OFFSET, LIMIT));
309     } catch (Exception e) {
310       throw new SpaceException(SpaceException.Code.ERROR_DATASTORE, e);
311     }
312   }
313 
314   /**
315    * {@inheritDoc}
316    */
317   public SpaceListAccess getPendingSpacesWithListAccess(String userId) {
318     return new SpaceListAccess(this.spaceStorage, userId, SpaceListAccess.Type.PENDING);
319   }
320 
321   /**
322    * {@inheritDoc}
323    */
324   public Space createSpace(Space space, String creator) {
325     return createSpace(space, creator, (String) null);
326   }
327 
328   /**
329    * {@inheritDoc}
330    */
331   @Deprecated
332   public Space createSpace(Space space, String creator, String invitedGroupId) {
333     List<Identity> invitedIdentities = new ArrayList<Identity>();
334     if (invitedGroupId != null) { // Invites users in group to join the new created space
335       // Gets identities of users in group and then invites them to join into space.
336       OrganizationService org = getOrgService();
337       try {
338         ListAccess<User> groupMembersAccess = org.getUserHandler().findUsersByGroupId(invitedGroupId);
339         User [] users = groupMembersAccess.load(0, groupMembersAccess.getSize());
340         for (User user : users) {
341           String userId = user.getUserName();
342           Identity identity = identityStorage.findIdentity(OrganizationIdentityProvider.NAME, userId);
343           if (identity != null) {
344             invitedIdentities.add(identity);
345           }
346         }
347       } catch (Exception e) {
348         throw new RuntimeException("Failed to invite users from group " + invitedGroupId, e);
349       }
350     }
351     return createSpace(space, creator, invitedIdentities);
352   }
353 
354   /**
355    * {@inheritDoc}
356    */
357   public Space createSpace(Space space, String creator, List<Identity> identitiesToInvite) {
358 
359     if (space.getDisplayName().length() > LIMIT) {
360       throw new RuntimeException("Error while creating the space " + space.getDisplayName() + ": space name cannot exceed 200 characters");
361     }
362 
363     if (!SpaceUtils.isValidSpaceName(space.getDisplayName())) {
364       throw new RuntimeException("Error while creating the space " + space.getDisplayName()+ ": space name can only contain letters, digits or space characters only");
365     }
366 
367     if(!spacesAdministrationService.canCreateSpace(creator)) {
368       throw new RuntimeException("User does not have permissions to create a space.");
369     }
370 
371     // Add creator as a manager and a member to this space
372     String[] managers = space.getManagers();
373     String[] members = space.getMembers();
374     managers = (String[]) ArrayUtils.add(managers,creator);
375     members = (String[]) ArrayUtils.add(members,creator);
376     space.setManagers(managers);
377     space.setMembers(members);
378 
379     // Creates new space by creating new group
380     String groupId = null;
381     try {
382       groupId = SpaceUtils.createGroup(space.getDisplayName(), space.getPrettyName(), creator);
383     } catch (SpaceException e) {
384       throw new RuntimeException("Error while creating group for space " + space.getPrettyName(), e);
385     }
386 
387     List<String> inviteds = new ArrayList<String>();
388     if (identitiesToInvite != null) {
389       Set<String> userIds = getUsersToInvite(identitiesToInvite);
390       userIds.remove(creator);
391       for (String userId : userIds) {
392         String[] invitedUsers = space.getInvitedUsers();
393         if (isSuperManager(userId)) {
394           members = space.getMembers();
395           if (!ArrayUtils.contains(members, userId)) {
396             members = (String[]) ArrayUtils.add(members, userId);
397             space.setMembers(members);
398           }
399         } else if (!ArrayUtils.contains(invitedUsers, userId)) {
400           invitedUsers = (String[]) ArrayUtils.add(invitedUsers, userId);
401           inviteds.add(userId);
402           space.setInvitedUsers(invitedUsers);
403         }
404       }
405     }
406 
407     String prettyName = groupId.split("/")[2];
408 
409     if (!prettyName.equals(space.getPrettyName())) {
410       //work around for SOC-2366
411       space.setPrettyName(groupId.split("/")[2]);
412     }
413 
414 
415     space.setGroupId(groupId);
416     space.setUrl(space.getPrettyName());
417 
418     try {
419       String spaceType = space.getTemplate();
420       SpaceTemplate spaceTemplate = spaceTemplateService.getSpaceTemplateByName(spaceType);
421       if (spaceTemplate == null) {
422         LOG.warn("could not find space template of type {}, will use Default template", spaceType);
423         String defaultTemplate = spaceTemplateService.getDefaultSpaceTemplate();
424         spaceTemplate = spaceTemplateService.getSpaceTemplateByName(defaultTemplate);
425         space.setTemplate(defaultTemplate);
426       }
427       String bannerPath = spaceTemplate.getBannerPath();
428       if (StringUtils.isNotBlank(bannerPath)) {
429         try {
430           InputStream bannerStream = configurationManager.getInputStream(bannerPath);
431           if (bannerStream != null) {
432             BannerAttachment bannerAttachment = new BannerAttachment(null, "banner", "png", bannerStream, null, System.currentTimeMillis());
433             space.setBannerAttachment(bannerAttachment);
434           }
435         } catch (Exception e) {
436           LOG.warn("No file found for space banner at path {}", bannerPath);
437         }
438       }
439       SpaceApplicationHandler applicationHandler = getSpaceApplicationHandler(space);
440       spaceTemplateService.initSpaceApplications(space, applicationHandler);
441     } catch (Exception e) {
442       throw new RuntimeException("Failed to init apps for space " + space.getPrettyName(), e);
443     }
444 
445     saveSpace(space, true);
446     spaceLifeCycle.spaceCreated(space, creator);
447 
448     //process invited user list
449     for (String invited : inviteds) {
450       spaceLifeCycle.addInvitedUser(space, invited);
451     }
452     updateSpaceBanner(space);
453     return space;
454   }
455 
456   private Set<String> getUsersToInvite(List<Identity> identities) {
457     Set<String> invitedUserIds = new HashSet<>();
458     for (Identity identity : identities) {
459       String providerId = identity.getProviderId();
460       String remoteId = identity.getRemoteId();
461       // If it's a space
462       if (SpaceIdentityProvider.NAME.equals(providerId)) {
463         Space space = getSpaceByPrettyName(remoteId);
464         if (space != null) {
465           String[] users = space.getMembers();
466           invitedUserIds.addAll(Arrays.asList(users));
467         }
468       } else { // Otherwise, it's an user
469         invitedUserIds.add(remoteId);
470       }
471     }
472     return invitedUserIds;
473   }
474 
475   /**
476    * {@inheritDoc}
477    */
478   public void saveSpace(Space space, boolean isNew) {
479     Space oldSpace = getSpaceById(space.getId());
480     spaceStorage.saveSpace(space, isNew);
481     if (!isNew) {
482       if (!oldSpace.getVisibility().equals(space.getVisibility())) {
483         spaceLifeCycle.spaceAccessEdited(space, space.getEditor());
484       }
485 
486       String oldRegistration = oldSpace.getRegistration();
487       String registration = space.getRegistration();
488       if ((oldRegistration == null && registration != null)
489           || (oldRegistration != null && !oldRegistration.equals(registration))) {
490         spaceLifeCycle.spaceRegistrationEdited(space, space.getEditor());
491       }
492     }
493   }
494 
495   /**
496    * {@inheritDoc}
497    */
498   public void renameSpace(Space space, String newDisplayName) {
499     spaceStorage.renameSpace(space, newDisplayName);
500     spaceLifeCycle.spaceRenamed(space, space.getEditor());
501   }
502 
503   /**
504    * {@inheritDoc}
505    */
506   public void renameSpace(String remoteId, Space space, String newDisplayName) {
507 
508     if (remoteId != null &&
509         isSuperManager(remoteId) &&
510         isMember(space, remoteId) == false) {
511 
512       spaceStorage.renameSpace(remoteId, space, newDisplayName);
513 
514     } else {
515 
516       spaceStorage.renameSpace(space, newDisplayName);
517     }
518 
519     //
520     spaceLifeCycle.spaceRenamed(space, space.getEditor());
521   }
522 
523   /**
524    * {@inheritDoc}
525    */
526   public void deleteSpace(Space space) {
527     try {
528       Identity spaceIdentity = identityStorage.findIdentity(SpaceIdentityProvider.NAME, space.getPrettyName());
529 
530       if (spaceIdentity != null) {
531         identityStorage.hardDeleteIdentity(spaceIdentity);
532       }
533 
534       // remove memberships of users with deleted space.
535       SpaceUtils.removeMembershipFromGroup(space);
536 
537       spaceStorage.deleteSpace(space.getId());
538 
539       OrganizationService orgService = getOrgService();
540       UserACL acl = getUserACL();
541       GroupHandler groupHandler = orgService.getGroupHandler();
542       Group deletedGroup = groupHandler.findGroupById(space.getGroupId());
543       List<String> mandatories = acl.getMandatoryGroups();
544       if (deletedGroup != null) {
545         if (!isMandatory(groupHandler, deletedGroup, mandatories)) {
546           SpaceUtils.removeGroup(space);
547         }
548       } else {
549         LOG.warn("deletedGroup is null");
550       }
551 
552       //remove pages and group navigation of space
553       SpaceUtils.removePagesAndGroupNavigation(space);
554 
555     } catch (Exception e) {
556       LOG.error("Unable delete space", e);
557     }
558     spaceLifeCycle.spaceRemoved(space, null);
559   }
560 
561   /**
562    * {@inheritDoc}
563    */
564   public void deleteSpace(String spaceId) {
565     deleteSpace(getSpaceById(spaceId));
566   }
567 
568   /**
569    * {@inheritDoc}
570    *
571    * @deprecated Uses {@link #initApps(Space)} instead.
572    */
573   public void initApp(Space space) throws SpaceException {
574     LOG.warn("Does nothing, just for compatible. It will be removed at 1.3.x");
575     return;
576   }
577 
578   /**
579    * {@inheritDoc}
580    */
581   public void initApps(Space space) throws SpaceException {
582     LOG.warn("Does nothing, just for compatible. It will be removed at 1.3.x");
583     return;
584   }
585 
586   /**
587    * {@inheritDoc}
588    */
589   public void deInitApps(Space space) throws SpaceException {
590     LOG.warn("Does nothing, just for compatible. It will be removed at 1.3.x");
591     return;
592   }
593 
594   /**
595    * {@inheritDoc}
596    */
597   public void addMember(Space space, String userId) {
598     String[] members = space.getMembers();
599     space = this.removeInvited(space, userId);
600     space = this.removePending(space, userId);
601     if (!ArrayUtils.contains(members, userId)) {
602       members = (String[]) ArrayUtils.add(members, userId);
603       space.setMembers(members);
604       this.updateSpace(space);
605       SpaceUtils.addUserToGroupWithMemberMembership(userId, space.getGroupId());
606       spaceLifeCycle.memberJoined(space, userId);
607     }
608   }
609 
610   /**
611    * {@inheritDoc}
612    */
613   public void addMember(String spaceId, String userId) {
614     addMember(getSpaceById(spaceId), userId);
615   }
616 
617   /**
618    * {@inheritDoc}
619    */
620   public void removeMember(Space space, String userId) {
621     Identity spaceIdentity = identityStorage.findIdentity(SpaceIdentityProvider.NAME, space.getPrettyName());
622     if (spaceIdentity != null && spaceIdentity.isDeleted()) {
623       return;
624     }
625     String[] members = space.getMembers();
626     if (ArrayUtils.contains(members, userId)) {
627       members = (String[]) ArrayUtils.removeElement(members, userId);
628       space.setMembers(members);
629       this.updateSpace(space);
630       SpaceUtils.removeUserFromGroupWithMemberMembership(userId, space.getGroupId());
631       spaceLifeCycle.memberLeft(space, userId);
632     }
633   }
634 
635   /**
636    * {@inheritDoc}
637    */
638   public void removeMember(String spaceId, String userId) {
639     removeMember(getSpaceById(spaceId), userId);
640   }
641 
642   /**
643    * {@inheritDoc}
644    */
645   private Space addPending(Space space, String userId) {
646     String[] pendingUsers = space.getPendingUsers();
647     if (!ArrayUtils.contains(pendingUsers, userId)) {
648       pendingUsers = (String[]) ArrayUtils.add(pendingUsers, userId);
649       space.setPendingUsers(pendingUsers);
650     }
651     return space;
652   }
653 
654   /**
655    * {@inheritDoc}
656    */
657   private Space removePending(Space space, String userId) {
658     String[] pendingUsers = space.getPendingUsers();
659     if (ArrayUtils.contains(pendingUsers, userId)) {
660       pendingUsers = (String[]) ArrayUtils.removeElement(pendingUsers, userId);
661       space.setPendingUsers(pendingUsers);
662     }
663     return space;
664   }
665 
666   /**
667    * {@inheritDoc}
668    */
669   private Space addInvited(Space space, String userId) {
670     String[] invitedUsers = space.getInvitedUsers();
671     if (!ArrayUtils.contains(invitedUsers, userId)) {
672       invitedUsers = (String[]) ArrayUtils.add(invitedUsers, userId);
673       space.setInvitedUsers(invitedUsers);
674     }
675     return space;
676   }
677 
678   /**
679    * {@inheritDoc}
680    */
681   private Space removeInvited(Space space, String userId) {
682     String[] invitedUsers = space.getInvitedUsers();
683     if (ArrayUtils.contains(invitedUsers, userId)) {
684       invitedUsers = (String[]) ArrayUtils.removeElement(invitedUsers, userId);
685       space.setInvitedUsers(invitedUsers);
686     }
687     return space;
688   }
689 
690   /**
691    * {@inheritDoc}
692    */
693   public List<String> getMembers(Space space) {
694     if (space.getMembers() != null) {
695       return Arrays.asList(space.getMembers());
696     }
697     return new ArrayList<String> ();
698   }
699 
700   /**
701    * {@inheritDoc}
702    */
703   public List<String> getMembers(String spaceId) {
704     return getMembers(getSpaceById(spaceId));
705   }
706 
707   /**
708    * {@inheritDoc}
709    * If isLeader == true, that user will be assigned "manager" membership and the "member" memberhship will be removed.
710    * Otherwise, that user will be assigned "member" membership and the "manager" membership will be removed.
711    * However, if that user is the only manager, that user is not allowed to be removed from the manager membership.
712    */
713   public void setLeader(Space space, String userId, boolean isLeader) {
714     this.setManager(space, userId, isLeader);
715   }
716 
717   /**
718    * {@inheritDoc}
719    *
720    * If isLeader == true, that user will be assigned "manager" membership and the "member" membership will be removed.
721    * Otherwise, that user will be assigned "member" membership and the "manager" membership will be removed.
722    */
723   public void setLeader(String spaceId, String userId, boolean isLeader) {
724     this.setManager(this.getSpaceById(spaceId), userId, isLeader);
725   }
726 
727   /**
728    * {@inheritDoc}
729    */
730   public boolean isLeader(Space space, String userId) {
731     return this.isManager(space, userId);
732   }
733 
734   /**
735    * {@inheritDoc}
736    */
737   public boolean isLeader(String spaceId, String userId) {
738     return this.isManager(this.getSpaceById(spaceId), userId);
739   }
740 
741   /**
742    * {@inheritDoc}
743    */
744   public boolean isOnlyLeader(Space space, String userId) {
745     return this.isOnlyManager(space, userId);
746   }
747 
748   /**
749    * {@inheritDoc}
750    */
751   public boolean isOnlyLeader(String spaceId, String userId) {
752     return this.isOnlyManager(this.getSpaceById(spaceId), userId);
753   }
754 
755   /**
756    * {@inheritDoc}
757    */
758   public boolean isMember(Space space, String userId) {
759     return ArrayUtils.contains(space.getMembers(), userId);
760   }
761 
762   /**
763    * {@inheritDoc}
764    */
765   public boolean isMember(String spaceId, String userId) {
766     return isMember(getSpaceById(spaceId), userId);
767   }
768 
769   /**
770    * {@inheritDoc}
771    */
772   public boolean hasAccessPermission(Space space, String userId) {
773     if (isSuperManager(userId)
774         || (ArrayUtils.contains(space.getMembers(), userId))
775         || (ArrayUtils.contains(space.getManagers(), userId))) {
776       return true;
777     }
778     return false;
779   }
780 
781   /**
782    * {@inheritDoc}
783    */
784   public boolean hasAccessPermission(String spaceId, String userId) {
785     return hasAccessPermission(getSpaceById(spaceId), userId);
786   }
787 
788   /**
789    * {@inheritDoc}
790    */
791   public boolean hasEditPermission(Space space, String userId) {
792     return this.hasSettingPermission(space, userId);
793   }
794 
795   /**
796    * {@inheritDoc}
797    */
798   public boolean hasEditPermission(String spaceId, String userId) {
799     return this.hasSettingPermission(this.getSpaceById(spaceId), userId);
800   }
801 
802   /**
803    * {@inheritDoc}
804    */
805   public boolean isInvited(Space space, String userId) {
806     return this.isInvitedUser(space, userId);
807   }
808 
809   /**
810    * {@inheritDoc}
811    */
812   public boolean isInvited(String spaceId, String userId) {
813     return this.isInvitedUser(this.getSpaceById(spaceId), userId);
814   }
815 
816   /**
817    * {@inheritDoc}
818    */
819   public boolean isPending(Space space, String userId) {
820     return this.isPendingUser(space, userId);
821   }
822 
823   /**
824    * {@inheritDoc}
825    */
826   public boolean isPending(String spaceId, String userId) {
827     return this.isPendingUser(this.getSpaceById(spaceId), userId);
828   }
829 
830   /**
831    * {@inheritDoc}
832    */
833   public boolean isIgnored(Space space, String userId) {
834     boolean ignoredMember = spaceStorage.isSpaceIgnored(space.getId(), userId);
835     return ignoredMember;
836   }
837 
838   /**
839    * {@inheritDoc}
840    */
841   public void setIgnored(String spaceId, String userId) {
842     spaceStorage.ignoreSpace(spaceId, userId);
843   }
844 
845   /**
846    * {@inheritDoc}
847    */
848   public void installApplication(String spaceId, String appId) throws SpaceException {
849     installApplication(getSpaceById(spaceId), appId);
850   }
851 
852   /**
853    * {@inheritDoc}
854    */
855   public void installApplication(Space space, String appId) throws SpaceException {
856     // String appStatus = SpaceUtils.getAppStatus(space, appId);
857     // if (appStatus != null) {
858     // if (appStatus.equals(Space.INSTALL_STATUS)) return;
859     // }
860     // SpaceApplicationHandler appHandler = getSpaceApplicationHandler(space);
861     // appHandler.installApplication(space, appId); // not implement yet
862     // setApp(space, appId, appId, SpaceUtils.isRemovableApp(space, appId),
863     // Space.INSTALL_STATUS);
864     spaceLifeCycle.addApplication(space, getPortletId(appId));
865   }
866 
867   /**
868    * {@inheritDoc}
869    */
870   public void activateApplication(Space space, String appId) throws SpaceException {
871     // String appStatus = SpaceUtils.getAppStatus(space, appId);
872     // if (appStatus != null) {
873     // if (appStatus.equals(Space.ACTIVE_STATUS)) return;
874     // }
875     String appName = null;
876     if (SpaceUtils.isInstalledApp(space, appId)) {
877       appName = appId + System.currentTimeMillis();
878     } else {
879       appName = appId;
880     }
881     SpaceApplicationHandler appHandler = getSpaceApplicationHandler(space);
882     appHandler.activateApplication(space, appId, appName);
883     // Default is removable, or must be added by configuration or support setting for applications.
884     spaceTemplateService.setApp(space, appId, appName, true, Space.ACTIVE_STATUS);
885     saveSpace(space, false);
886     // Use portletId instead of appId for fixing SOC-1633.
887     spaceLifeCycle.activateApplication(space, getPortletId(appId));
888   }
889 
890   /**
891    * {@inheritDoc}
892    */
893   public void activateApplication(String spaceId, String appId) throws SpaceException {
894     activateApplication(getSpaceById(spaceId), appId);
895   }
896 
897   /**
898    * {@inheritDoc}
899    */
900   public void deactivateApplication(Space space, String appId) throws SpaceException {
901     String appStatus = SpaceUtils.getAppStatus(space, appId);
902     if (appStatus == null) {
903       LOG.warn("appStatus is null!");
904       return;
905     }
906     if (appStatus.equals(Space.DEACTIVE_STATUS))
907       return;
908     SpaceApplicationHandler appHandler = getSpaceApplicationHandler(space);
909     appHandler.deactiveApplication(space, appId);
910     spaceTemplateService.setApp(space, appId, appId, SpaceUtils.isRemovableApp(space, appId), Space.DEACTIVE_STATUS);
911     saveSpace(space, false);
912     spaceLifeCycle.deactivateApplication(space, getPortletId(appId));
913   }
914 
915   /**
916    * {@inheritDoc}
917    */
918   public void deactivateApplication(String spaceId, String appId) throws SpaceException {
919     deactivateApplication(getSpaceById(spaceId), appId);
920   }
921 
922   /**
923    * {@inheritDoc}
924    */
925   public void removeApplication(Space space, String appId, String appName) throws SpaceException {
926     String appStatus = SpaceUtils.getAppStatus(space, appId);
927     if (appStatus == null)
928       return;
929     SpaceApplicationHandler appHandler = getSpaceApplicationHandler(space);
930     appHandler.removeApplication(space, appId, appName);
931     removeApp(space, appId, appName);
932     spaceLifeCycle.removeApplication(space, getPortletId(appId));
933   }
934 
935   /**
936    * {@inheritDoc}
937    */
938   public void removeApplication(String spaceId, String appId, String appName) throws SpaceException {
939     removeApplication(getSpaceById(spaceId), appId, appName);
940   }
941 
942   /**
943    * {@inheritDoc}
944    */
945   public void requestJoin(String spaceId, String userId) {
946     this.addPendingUser(this.getSpaceById(spaceId), userId);
947   }
948 
949   /**
950    * {@inheritDoc}
951    */
952   public void requestJoin(Space space, String userId) {
953     this.addPendingUser(space, userId);
954   }
955 
956   /**
957    * {@inheritDoc}
958    */
959   public void revokeRequestJoin(Space space, String userId) {
960     this.removePendingUser(space, userId);
961   }
962 
963   /**
964    * {@inheritDoc}
965    */
966   public void revokeRequestJoin(String spaceId, String userId) {
967     this.removePending(this.getSpaceById(spaceId), userId);
968   }
969 
970   /**
971    * {@inheritDoc}
972    */
973   public void inviteMember(Space space, String userId) {
974     this.addInvitedUser(space, userId);
975   }
976 
977   /**
978    * {@inheritDoc}
979    */
980   public void inviteMember(String spaceId, String userId) {
981     this.addInvitedUser(this.getSpaceById(spaceId), userId);
982   }
983 
984   /**
985    * {@inheritDoc}
986    */
987   public void revokeInvitation(Space space, String userId) {
988     this.removeInvitedUser(space, userId);
989   }
990 
991   /**
992    * {@inheritDoc}
993    */
994   public void revokeInvitation(String spaceId, String userId) {
995     this.removeInvitedUser(this.getSpaceById(spaceId), userId);
996   }
997 
998   /**
999    * {@inheritDoc}
1000    */
1001   public void acceptInvitation(Space space, String userId) throws SpaceException {
1002     this.addMember(space, userId);
1003   }
1004 
1005   /**
1006    * {@inheritDoc}
1007    */
1008   public void acceptInvitation(String spaceId, String userId) throws SpaceException {
1009     this.addMember(this.getSpaceById(spaceId), userId);
1010   }
1011 
1012   /**
1013    * {@inheritDoc}
1014    */
1015   public void denyInvitation(String spaceId, String userId) {
1016     this.removeInvitedUser(this.getSpaceById(spaceId), userId);
1017   }
1018 
1019   /**
1020    * {@inheritDoc}
1021    */
1022   public void denyInvitation(Space space, String userId) {
1023     this.removeInvitedUser(space, userId);
1024   }
1025 
1026   /**
1027    * {@inheritDoc}
1028    */
1029   public void validateRequest(Space space, String userId) {
1030     this.addMember(space, userId);
1031   }
1032 
1033   /**
1034    * {@inheritDoc}
1035    */
1036   public void validateRequest(String spaceId, String userId) {
1037     this.addMember(this.getSpaceById(spaceId), userId);
1038   }
1039 
1040   /**
1041    * {@inheritDoc}
1042    */
1043   public void declineRequest(Space space, String userId) {
1044     this.removePendingUser(space, userId);
1045   }
1046 
1047   /**
1048    * {@inheritDoc}
1049    */
1050   public void declineRequest(String spaceId, String userId) {
1051     this.removePendingUser(this.getSpaceById(spaceId), userId);
1052   }
1053 
1054   /**
1055    * {@inheritDoc}
1056    */
1057   public void registerSpaceLifeCycleListener(SpaceLifeCycleListener listener) {
1058     spaceLifeCycle.addListener(listener);
1059   }
1060 
1061   /**
1062    * {@inheritDoc}
1063    */
1064   public void unregisterSpaceLifeCycleListener(SpaceLifeCycleListener listener) {
1065     spaceLifeCycle.removeListener(listener);
1066   }
1067 
1068   public void addSpaceListener(SpaceListenerPlugin plugin) {
1069     registerSpaceLifeCycleListener(plugin);
1070   }
1071 
1072   /**
1073    * Set portlet preferences from plug-in into local variable.
1074    */
1075   public void setPortletsPrefsRequired(PortletPreferenceRequiredPlugin portletPrefsRequiredPlugin) {
1076     List<String> portletPrefs = portletPrefsRequiredPlugin.getPortletPrefs();
1077     if (portletPrefsRequired == null) {
1078       portletPrefsRequired = new ArrayList<String>();
1079     }
1080     portletPrefsRequired.addAll(portletPrefs);
1081   }
1082 
1083   /**
1084    * Get portlet preferences required for using in create portlet application.
1085    */
1086   public String [] getPortletsPrefsRequired() {
1087     return this.portletPrefsRequired.toArray(new String[this.portletPrefsRequired.size()]);
1088   }
1089 
1090   /**
1091    * Gets OrganizationService
1092    *
1093    * @return organizationService
1094    */
1095   private OrganizationService getOrgService() {
1096     if (orgService == null) {
1097       ExoContainer container = ExoContainerContext.getCurrentContainer();
1098       orgService = (OrganizationService) container.getComponentInstanceOfType(OrganizationService.class);
1099     }
1100     return orgService;
1101   }
1102 
1103   /**
1104    * Gets UserACL
1105    *
1106    * @return userACL
1107    */
1108   private UserACL getUserACL() {
1109     return userACL;
1110   }
1111 
1112   /**
1113    * Gets space application handler
1114    *
1115    * @param space
1116    * @return
1117    * @throws SpaceException
1118    */
1119   private SpaceApplicationHandler getSpaceApplicationHandler(Space space) throws SpaceException {
1120     String spaceTemplate = space.getTemplate();
1121     SpaceApplicationHandler appHandler = spaceTemplateService.getSpaceApplicationHandlers().get(spaceTemplate);
1122     if (appHandler == null) {
1123       LOG.debug("No space application handler was defined for template with name {}. Default will be used.", spaceTemplate);
1124       String defaultTemplate = spaceTemplateService.getDefaultSpaceTemplate();
1125       appHandler = spaceTemplateService.getSpaceApplicationHandlers().get(defaultTemplate);
1126       if (appHandler == null) {
1127         throw new SpaceException(SpaceException.Code.UNKNOWN_SPACE_TYPE);
1128       }
1129     }
1130     return appHandler;
1131   }
1132 
1133   /**
1134    * Removes application from a space
1135    *
1136    * @param space
1137    * @param appId
1138    * @throws SpaceException
1139    */
1140   private void removeApp(Space space, String appId, String appName) throws SpaceException {
1141     String apps = space.getApp();
1142     StringBuffer remainApp = new StringBuffer();
1143     String[] listApp = apps.split(",");
1144     String[] appPart;
1145     String app;
1146     for (int idx = 0; idx < listApp.length; idx++) {
1147       app = listApp[idx];
1148       appPart = app.split(":");
1149       if (!appPart[1].equals(appName)) {
1150         if (remainApp.length() != 0)
1151           remainApp.append(",");
1152         remainApp.append(app);
1153       }
1154     }
1155 
1156     space.setApp(remainApp.toString());
1157     saveSpace(space, false);
1158   }
1159 
1160   private boolean isMandatory(GroupHandler groupHandler, Group group, List<String> mandatories) throws Exception {
1161     if (mandatories.contains(group.getId()))
1162       return true;
1163     Collection<Group> children = groupHandler.findGroups(group);
1164     for (Group g : children) {
1165       if (isMandatory(groupHandler, g, mandatories))
1166         return true;
1167     }
1168     return false;
1169   }
1170 
1171   /**
1172    * @return
1173    * @deprecated To be removed at 1.3.x.
1174    */
1175   public SpaceStorage getStorage() {
1176     return spaceStorage;
1177   }
1178 
1179   /**
1180    *
1181    * @param storage
1182    * @deprecated  To be removed at 1.3.x
1183    */
1184   public void setStorage(SpaceStorage storage) {
1185     this.spaceStorage = storage;
1186   }
1187 
1188   /**
1189    * {@inheritDoc}
1190    */
1191   public void addInvitedUser(Space space, String userId) {
1192 
1193     if (ArrayUtils.contains(space.getMembers(),userId)) {
1194       //user is already member. Do nothing
1195       return;
1196     }
1197 
1198     if (isPending(space, userId)) {
1199       space = removePending(space, userId);
1200       addMember(space, userId);
1201     } else {
1202       space = addInvited(space, userId);
1203     }
1204     this.updateSpace(space);
1205     spaceLifeCycle.addInvitedUser(space, userId);
1206   }
1207 
1208   /**
1209    * {@inheritDoc}
1210    */
1211   public void addPendingUser(Space space, String userId) {
1212     if (ArrayUtils.contains(space.getMembers(),userId)) {
1213       //user is already member. Do nothing
1214       return;
1215     }
1216 
1217     if (ArrayUtils.contains(space.getPendingUsers(), userId)) {
1218       this.addMember(space, userId);
1219       space = removeInvited(space, userId);
1220       this.updateSpace(space);
1221       return;
1222     }
1223 
1224     String registration = space.getRegistration();
1225     String visibility = space.getVisibility();
1226     if (visibility.equals(Space.HIDDEN) && registration.equals(Space.CLOSE)) {
1227       LOG.warn("Unable request to join hidden");
1228       return;
1229     }
1230     if (registration.equals(Space.OPEN)) {
1231       addMember(space, userId);
1232     } else if (registration.equals(Space.VALIDATION)) {
1233       space = addPending(space, userId);
1234       saveSpace(space, false);
1235     } else {
1236       LOG.warn("Unable request to join");
1237     }
1238     spaceLifeCycle.addPendingUser(space, userId);
1239   }
1240 
1241   /**
1242    * {@inheritDoc}
1243    */
1244   public ListAccess<Space> getAccessibleSpacesByFilter(String userId, SpaceFilter spaceFilter) {
1245     if (isSuperManager(userId)
1246         && (spaceFilter == null || spaceFilter.getAppId() == null)) {
1247       if(spaceFilter == null) {
1248         return new SpaceListAccess(this.spaceStorage, spaceFilter, SpaceListAccess.Type.ALL);
1249       } else {
1250         return new SpaceListAccess(this.spaceStorage, spaceFilter, SpaceListAccess.Type.ALL_FILTER);
1251       }
1252     } else {
1253       return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.ACCESSIBLE_FILTER);
1254     }
1255   }
1256 
1257   /**
1258    * {@inheritDoc}
1259    */
1260   public ListAccess<Space> getAllSpacesByFilter(SpaceFilter spaceFilter) {
1261     return new SpaceListAccess(this.spaceStorage, spaceFilter, SpaceListAccess.Type.ALL_FILTER);
1262   }
1263 
1264   /**
1265    * {@inheritDoc}
1266    */
1267   public ListAccess<Space> getInvitedSpacesByFilter(String userId, SpaceFilter spaceFilter) {
1268     return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.INVITED_FILTER);
1269   }
1270 
1271   /**
1272    * {@inheritDoc}
1273    */
1274   public ListAccess<Space> getMemberSpaces(String userId) {
1275     return new SpaceListAccess(this.spaceStorage, userId, SpaceListAccess.Type.MEMBER);
1276   }
1277 
1278   /**
1279    * {@inheritDoc}
1280    */
1281   public ListAccess<Space> getMemberSpacesByFilter(String userId, SpaceFilter spaceFilter) {
1282     return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.MEMBER_FILTER);
1283   }
1284 
1285   /**
1286    * {@inheritDoc}
1287    */
1288   public ListAccess<Space> getPendingSpacesByFilter(String userId, SpaceFilter spaceFilter) {
1289     return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.PENDING_FILTER);
1290   }
1291 
1292   /**
1293    * {@inheritDoc}
1294    */
1295   public ListAccess<Space> getPublicSpacesByFilter(String userId, SpaceFilter spaceFilter) {
1296     if (isSuperManager(userId)) {
1297       return new SpaceListAccess(this.spaceStorage, SpaceListAccess.Type.PUBLIC_SUPER_USER);
1298     } else {
1299       return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.PUBLIC_FILTER);
1300     }
1301   }
1302 
1303   /**
1304    * {@inheritDoc}
1305    */
1306   public ListAccess<Space> getSettingableSpaces(String userId) {
1307     if (isSuperManager(userId)) {
1308       return new SpaceListAccess(this.spaceStorage, SpaceListAccess.Type.ALL);
1309     } else {
1310       return new SpaceListAccess(this.spaceStorage, userId, SpaceListAccess.Type.SETTING);
1311     }
1312   }
1313 
1314   /**
1315    * {@inheritDoc}
1316    */
1317   public ListAccess<Space> getSettingabledSpacesByFilter(String userId, SpaceFilter spaceFilter) {
1318     if (isSuperManager(userId)) {
1319       return new SpaceListAccess(this.spaceStorage, spaceFilter, SpaceListAccess.Type.ALL_FILTER);
1320     } else {
1321       return new SpaceListAccess(this.spaceStorage, userId, spaceFilter, SpaceListAccess.Type.SETTING_FILTER);
1322     }
1323   }
1324 
1325   /**
1326    * {@inheritDoc}
1327    */
1328   public boolean hasSettingPermission(Space space, String userId) {
1329     return isSuperManager(userId) || ArrayUtils.contains(space.getManagers(), userId);
1330   }
1331 
1332   /**
1333    * {@inheritDoc}
1334    */
1335   public boolean isInvitedUser(Space space, String userId) {
1336     return ArrayUtils.contains(space.getInvitedUsers(), userId);
1337   }
1338 
1339   /**
1340    * {@inheritDoc}
1341    */
1342   public boolean isManager(Space space, String userId) {
1343     return ArrayUtils.contains(space.getManagers(), userId);
1344   }
1345 
1346   /**
1347    * {@inheritDoc}
1348    */
1349   public boolean isOnlyManager(Space space, String userId) {
1350     if (space.getManagers() != null && space.getManagers().length == 1 && ArrayUtils.contains(space.getManagers(), userId)) {
1351       return true;
1352     }
1353     return false;
1354   }
1355 
1356   /**
1357    * {@inheritDoc}
1358    */
1359   public boolean isPendingUser(Space space, String userId) {
1360     return ArrayUtils.contains(space.getPendingUsers(), userId);
1361   }
1362 
1363   /**
1364    * {@inheritDoc}
1365    */
1366   public void registerSpaceListenerPlugin(SpaceListenerPlugin spaceListenerPlugin) {
1367     spaceLifeCycle.addListener(spaceListenerPlugin);
1368   }
1369 
1370   /**
1371    * {@inheritDoc}
1372    */
1373   public void removeInvitedUser(Space space, String userId) {
1374     if (ArrayUtils.contains(space.getInvitedUsers(), userId)) {
1375       space = this.removeInvited(space, userId);
1376       this.updateSpace(space);
1377       removeWebNotifications(space.getId(), userId);
1378     }
1379   }
1380 
1381   /**
1382    * {@inheritDoc}
1383    */
1384   public void removePendingUser(Space space, String userId) {
1385     if (ArrayUtils.contains(space.getPendingUsers(), userId)) {
1386       space = this.removePending(space, userId);
1387       this.updateSpace(space);
1388       removeWebNotifications(space.getId(), userId);
1389     }
1390   }
1391 
1392   private void removeWebNotifications(String spaceId, String userId) {
1393     if (webNotificationService != null) {
1394       WebNotificationFilter filter = new WebNotificationFilter(userId);
1395       filter.setParameter("spaceId", spaceId);
1396       PluginKey pluginKey = new PluginKey("SpaceInvitationPlugin");
1397       filter.setPluginKey(pluginKey);
1398       try {
1399         for (NotificationInfo notificationInfo : webNotificationService.getNotificationInfos(filter, 0, -1)) {
1400           webNotificationService.remove(notificationInfo.getId());
1401         }
1402       } catch (Exception e) {
1403         LOG.error("Cannot remove web notifications for user: " + userId + " and space id: " + spaceId, e);
1404       }
1405     } else {
1406       LOG.error("Cannot update web notfication. WebNotificationService is null");
1407     }
1408   }
1409 
1410   /**
1411    * {@inheritDoc}
1412    */
1413   public void setManager(Space space, String userId, boolean isManager) {
1414     String[] managers = space.getManagers();
1415     if (isManager) {
1416       if (!ArrayUtils.contains(managers, userId)) {
1417         managers = (String[]) ArrayUtils.add(managers, userId);
1418         space.setManagers(managers);
1419         this.updateSpace(space);
1420         SpaceUtils.addUserToGroupWithManagerMembership(userId, space.getGroupId());
1421         spaceLifeCycle.grantedLead(space, userId);
1422       }
1423     } else {
1424       if (ArrayUtils.contains(managers, userId)) {
1425         managers = (String[]) ArrayUtils.removeElement(managers, userId);
1426         space.setManagers(managers);
1427         this.updateSpace(space);
1428         SpaceUtils.removeUserFromGroupWithManagerMembership(userId, space.getGroupId());
1429         Space updatedSpace = getSpaceById(space.getId());
1430         if (isMember(updatedSpace, userId)) {
1431           spaceLifeCycle.revokedLead(space, userId);
1432         }
1433       }
1434     }
1435   }
1436 
1437   /**
1438    * {@inheritDoc}
1439    */
1440   public void unregisterSpaceListenerPlugin(SpaceListenerPlugin spaceListenerPlugin) {
1441     spaceLifeCycle.removeListener(spaceListenerPlugin);
1442   }
1443 
1444   @Override
1445   @Deprecated
1446   public void setSpaceApplicationConfigPlugin(SpaceApplicationConfigPlugin spaceApplicationConfigPlugin) {
1447     LOG.warn("setSpaceApplicationConfigPlugin method has been deprecated, please use addSpaceTemplateConfigPlugin method from SpaceTemplateConfigPlugin class");
1448   }
1449 
1450   @Override
1451   @Deprecated
1452   public SpaceApplicationConfigPlugin getSpaceApplicationConfigPlugin() {
1453     return null;
1454   }
1455 
1456   /**
1457    * {@inheritDoc}
1458    */
1459   public Space updateSpace(Space existingSpace) {
1460     spaceStorage.saveSpace(existingSpace, false);
1461     if (UpdatedField.DESCRIPTION.equals(existingSpace.getField())) {
1462       spaceLifeCycle.spaceDescriptionEdited(existingSpace, existingSpace.getEditor());
1463     }
1464     return existingSpace;
1465   }
1466 
1467   public Space updateSpaceAvatar(Space existingSpace) {
1468     checkSpaceEditorPermissions(existingSpace);
1469 
1470     Identity spaceIdentity = identityStorage.findIdentity(SpaceIdentityProvider.NAME, existingSpace.getPrettyName());
1471     Profile profile = spaceIdentity.getProfile();
1472     if(existingSpace.getAvatarAttachment() != null) {
1473       profile.setProperty(Profile.AVATAR, existingSpace.getAvatarAttachment());
1474     } else {
1475       profile.removeProperty(Profile.AVATAR);
1476       profile.setAvatarUrl(null);
1477       profile.setAvatarLastUpdated(null);
1478     }
1479     identityStorage.updateProfile(profile);
1480     spaceLifeCycle.spaceAvatarEdited(existingSpace, existingSpace.getEditor());
1481     return existingSpace;
1482   }
1483 
1484   public Space updateSpaceBanner(Space existingSpace) {
1485     checkSpaceEditorPermissions(existingSpace);
1486 
1487     Identity spaceIdentity = identityStorage.findIdentity(SpaceIdentityProvider.NAME, existingSpace.getPrettyName());
1488     if (spaceIdentity != null) {
1489       Profile profile = spaceIdentity.getProfile();
1490       if (existingSpace.getBannerAttachment() != null) {
1491         profile.setProperty(Profile.BANNER, existingSpace.getBannerAttachment());
1492       } else {
1493         profile.removeProperty(Profile.BANNER);
1494       }
1495       identityStorage.updateProfile(profile);
1496       spaceLifeCycle.spaceBannerEdited(existingSpace, existingSpace.getEditor());
1497     } else {
1498       throw new IllegalStateException("Can not update space banner. Space identity " + existingSpace.getPrettyName() + " not found");
1499     }
1500     return existingSpace;
1501   }
1502 
1503   /**
1504    * {@inheritDoc}
1505    */
1506   public ListAccess<Space> getInvitedSpacesWithListAccess(String userId) {
1507     return new SpaceListAccess(this.spaceStorage, userId, SpaceListAccess.Type.INVITED);
1508   }
1509 
1510   /**
1511    * Returns portlet id.
1512    */
1513   private String getPortletId(String appId) {
1514     final char SEPARATOR = '.';
1515 
1516     if (appId.indexOf(SEPARATOR) != -1) {
1517       int beginIndex = appId.lastIndexOf(SEPARATOR) + 1;
1518       int endIndex = appId.length();
1519 
1520       return appId.substring(beginIndex, endIndex);
1521     }
1522 
1523     return appId;
1524   }
1525 
1526   @Override
1527   public void updateSpaceAccessed(String remoteId, Space space) throws SpaceException {
1528     if (isMember(space, remoteId)) {
1529       spaceStorage.updateSpaceAccessed(remoteId, space);
1530     }
1531   }
1532 
1533   @Override
1534   public List<Space> getLastAccessedSpace(String remoteId, String appId, int offset, int limit) throws SpaceException {
1535     SpaceFilter filter = new SpaceFilter(remoteId, appId);
1536     return spaceStorage.getLastAccessedSpace(filter, offset, limit);
1537   }
1538 
1539   public List<Space> getLastSpaces(int limit) {
1540     return spaceStorage.getLastSpaces(limit);
1541   }
1542 
1543   @Override
1544   public ListAccess<Space> getLastAccessedSpace(String remoteId, String appId) {
1545     return new SpaceListAccess(this.spaceStorage, remoteId, appId, SpaceListAccess.Type.LASTEST_ACCESSED);
1546   }
1547 
1548   public ListAccess<Space> getVisitedSpaces(String remoteId, String appId) {
1549     return new SpaceListAccess(this.spaceStorage, remoteId, appId, SpaceListAccess.Type.VISITED);
1550   }
1551 
1552   /**
1553    * {@inheritDoc}
1554    */
1555   @Override
1556   public boolean isSuperManager(String userId) {
1557     if (StringUtils.isBlank(userId) || IdentityConstants.ANONIM.equals(userId) || IdentityConstants.SYSTEM.equals(userId)) {
1558       return false;
1559     }
1560     if (userId.equals(getUserACL().getSuperUser())) {
1561       return true;
1562     }
1563     org.exoplatform.services.security.Identity identity = identityRegistry.getIdentity(userId);
1564     if (identity == null) {
1565       Collection<Membership> memberships;
1566       try {
1567         memberships = getOrgService().getMembershipHandler().findMembershipsByUser(userId);
1568       } catch (Exception e) {
1569         throw new RuntimeException("Can't get user '" + userId + "' memberships", e);
1570       }
1571       List<MembershipEntry> entries = new ArrayList<>();
1572       for (Membership membership : memberships) {
1573         entries.add(new MembershipEntry(membership.getGroupId(), membership.getMembershipType()));
1574       }
1575       identity = new org.exoplatform.services.security.Identity(userId, entries);
1576     }
1577     List<MembershipEntry> superManagersMemberships = spacesAdministrationService.getSpacesAdministratorsMemberships();
1578     if (superManagersMemberships != null && !superManagersMemberships.isEmpty()) {
1579       for (MembershipEntry superManagerMembership : superManagersMemberships) {
1580         if (identity.isMemberOf(superManagerMembership)) {
1581           return true;
1582         }
1583       }
1584     }
1585     return false;
1586   }
1587 
1588   private String checkSpaceEditorPermissions(Space space) {
1589     String editor = space.getEditor();
1590     // TODO if the space editor is null, an exception should be thrown too
1591     if (StringUtils.isNotBlank(editor) && !hasEditPermission(space, editor)) {
1592       throw new IllegalStateException("User " + editor + " is not authorized to change space.");
1593     }
1594     return editor;
1595   }
1596 }