View Javadoc
1   /*
2    * Copyright (C) 2003-2011 eXo Platform SAS.
3    *
4    * This program is free software: you can redistribute it and/or modify
5    * it under the terms of the GNU Affero General Public License as published by
6    * the Free Software Foundation, either version 3 of the License, or
7    * (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 Affero General Public License for more details.
13   *
14   * You should have received a copy of the GNU Affero General Public License
15   * along with this program. If not, see <http://www.gnu.org/licenses/>.
16   */
17  
18  package org.exoplatform.social.core.storage.impl;
19  
20  import org.apache.commons.lang.StringEscapeUtils;
21  import org.chromattic.api.ChromatticSession;
22  import org.chromattic.api.query.Ordering;
23  import org.chromattic.api.query.Query;
24  import org.chromattic.api.query.QueryBuilder;
25  import org.chromattic.api.query.QueryResult;
26  import org.chromattic.core.api.ChromatticSessionImpl;
27  
28  import org.exoplatform.container.PortalContainer;
29  import org.exoplatform.services.log.ExoLogger;
30  import org.exoplatform.services.log.Log;
31  import org.exoplatform.social.core.chromattic.entity.IdentityEntity;
32  import org.exoplatform.social.core.chromattic.entity.ProviderEntity;
33  import org.exoplatform.social.core.chromattic.entity.SpaceEntity;
34  import org.exoplatform.social.core.chromattic.entity.SpaceListEntity;
35  import org.exoplatform.social.core.chromattic.entity.SpaceRef;
36  import org.exoplatform.social.core.chromattic.entity.SpaceRootEntity;
37  import org.exoplatform.social.core.identity.model.Identity;
38  import org.exoplatform.social.core.identity.model.Profile;
39  import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider;
40  import org.exoplatform.social.core.identity.provider.SpaceIdentityProvider;
41  import org.exoplatform.social.core.search.Sorting;
42  import org.exoplatform.social.core.service.LinkProvider;
43  import org.exoplatform.social.core.space.SpaceFilter;
44  import org.exoplatform.social.core.space.SpaceUtils;
45  import org.exoplatform.social.core.space.model.Space;
46  import org.exoplatform.social.core.storage.SpaceStorageException;
47  import org.exoplatform.social.core.storage.api.SpaceStorage;
48  import org.exoplatform.social.core.storage.exception.NodeNotFoundException;
49  import org.exoplatform.social.core.storage.query.JCRProperties;
50  import org.exoplatform.social.core.storage.query.QueryFunction;
51  import org.exoplatform.social.core.storage.query.WhereExpression;
52  import org.exoplatform.social.core.storage.streams.StreamInvocationHelper;
53  
54  import java.util.ArrayList;
55  import java.util.Arrays;
56  import java.util.Collection;
57  import java.util.Collections;
58  import java.util.HashSet;
59  import java.util.Iterator;
60  import java.util.LinkedHashMap;
61  import java.util.LinkedList;
62  import java.util.List;
63  import java.util.Map;
64  import java.util.Map.Entry;
65  import java.util.Set;
66  
67  import javax.jcr.Node;
68  import javax.jcr.Property;
69  import javax.jcr.RepositoryException;
70  
71  /**
72   * Space storage layer.
73   *
74   * @author <a href="mailto:alain.defrance@exoplatform.com">Alain Defrance</a>
75   * @version $Revision$
76   */
77  public class SpaceStorageImpl extends AbstractStorage implements SpaceStorage {
78  
79    /** Logger */
80    private static final Log LOG = ExoLogger.getLogger(SpaceStorageImpl.class);
81  
82    /**
83     * The identity storage
84     */
85    private IdentityStorageImpl identityStorage;
86  
87    private static final int TWO_SECONDS = 2000;
88    
89    /**
90     * Constructor.
91     *
92     * @param identityStorage the identity storage
93     */
94    public SpaceStorageImpl(IdentityStorageImpl identityStorage) {
95     this.identityStorage = identityStorage;
96   }
97  
98    public void setIdentityStorage(IdentityStorageImpl identityStorage) {
99      this.identityStorage = identityStorage;
100   }
101 
102   /**
103    * Fills {@link Space}'s properties to {@link SpaceEntity}'s.
104    *
105    * @param entity the space entity from chromattic
106    * @param space  the space pojo for services
107    */
108   private void fillSpaceFromEntity(SpaceEntity entity, Space space) {
109 
110     space.setApp(entity.getApp());
111     space.setId(entity.getId());
112     space.setDisplayName(entity.getDisplayName());
113     space.setPrettyName(entity.getPrettyName());
114     space.setRegistration(entity.getRegistration());
115     space.setDescription(entity.getDescription());
116     space.setType(entity.getType());
117     space.setVisibility(entity.getVisibility());
118     space.setPriority(entity.getPriority());
119     space.setGroupId(entity.getGroupId());
120     space.setUrl(entity.getURL());
121     space.setPendingUsers(entity.getPendingMembersId());
122     space.setInvitedUsers(entity.getInvitedMembersId());
123     space.setCreatedTime(entity.getCreatedTime());
124 
125     //
126     String[] members = entity.getMembersId();
127     String[] managers = entity.getManagerMembersId();
128 
129     //
130     Set<String> membersList = new HashSet<String>();
131     if (members != null) membersList.addAll(Arrays.asList(members));
132     if (managers != null) membersList.addAll(Arrays.asList(managers));
133 
134     //
135     space.setMembers(membersList.toArray(new String[]{}));
136     space.setManagers(entity.getManagerMembersId());
137 
138 
139     if (entity.getAvatarLastUpdated() != null) {
140       try {
141         PortalContainer container = PortalContainer.getInstance();
142         ChromatticSession chromatticSession = getSession();
143         String url = String.format("/%s/jcr/%s/%s/production/soc:providers/soc:space/soc:%s/soc:profile/soc:avatar/?upd=%d",
144             container.getRestContextName(),
145             lifeCycle.getRepositoryName(),
146             chromatticSession.getJCRSession().getWorkspace().getName(),
147             entity.getPrettyName(),
148             entity.getAvatarLastUpdated());
149         space.setAvatarUrl(LinkProvider.escapeJCRSpecialCharacters(url));
150       } catch (Exception e) {
151         LOG.warn("Failed to build avatar url: " + e.getMessage());
152       }
153     }
154     space.setAvatarLastUpdated(entity.getAvatarLastUpdated());
155   }
156   
157   /**
158    * Fills {@link Space}'s properties to {@link SpaceEntity}'s.
159    *
160    * @param entity the space entity from chromattic
161    * @param space  the space pojo for services
162    */
163   private void fillSpaceSimpleFromEntity(SpaceEntity entity, Space space) {
164 
165     space.setId(entity.getId());
166     space.setDisplayName(entity.getDisplayName());
167     space.setPrettyName(entity.getPrettyName());
168     space.setDescription(entity.getDescription());
169     space.setGroupId(entity.getGroupId());
170     space.setUrl(entity.getURL());
171     space.setCreatedTime(entity.getCreatedTime());
172 
173     if (entity.getAvatarLastUpdated() != null) {
174       try {
175         PortalContainer container = PortalContainer.getInstance();
176         ChromatticSession chromatticSession = getSession();
177         String url = String.format("/%s/jcr/%s/%s/production/soc:providers/soc:space/soc:%s/soc:profile/soc:avatar/?upd=%d",
178             container.getRestContextName(),
179             lifeCycle.getRepositoryName(),
180             chromatticSession.getJCRSession().getWorkspace().getName(),
181             entity.getPrettyName(),
182             entity.getAvatarLastUpdated());
183         space.setAvatarUrl(LinkProvider.escapeJCRSpecialCharacters(url));
184       } catch (Exception e) {
185         LOG.warn("Failed to build avatar url: " + e.getMessage());
186       }
187     }
188     space.setAvatarLastUpdated(entity.getAvatarLastUpdated());
189   }
190 
191   /**
192    * Fills {@link SpaceEntity}'s properties from {@link Space}'s.
193    *
194    * @param space the space pojo for services
195    * @param entity the space entity from chromattic
196    */
197   private void fillEntityFromSpace(Space space, SpaceEntity entity) {
198     
199     entity.setName(space.getPrettyName());
200     
201     entity.setApp(space.getApp());
202     entity.setPrettyName(space.getPrettyName());
203     entity.setDisplayName(space.getDisplayName());
204     entity.setRegistration(space.getRegistration());
205     entity.setDescription(space.getDescription());
206     entity.setType(space.getType());
207     entity.setVisibility(space.getVisibility());
208     entity.setPriority(space.getPriority());
209     entity.setGroupId(space.getGroupId());
210     entity.setURL(space.getUrl());
211     entity.setMembersId(space.getMembers());
212     entity.setManagerMembersId(space.getManagers());
213     entity.setPendingMembersId(space.getPendingUsers());
214     entity.setInvitedMembersId(space.getInvitedUsers());
215     entity.setAvatarLastUpdated(space.getAvatarLastUpdated());
216     entity.setCreatedTime(space.getCreatedTime() != 0 ? space.getCreatedTime() : System.currentTimeMillis());
217   }
218 
219   private void applyOrder(QueryBuilder builder, SpaceFilter spaceFilter) {
220 
221     //
222     Sorting sorting;
223     if (spaceFilter == null) {
224       sorting = new Sorting(Sorting.SortBy.TITLE, Sorting.OrderBy.ASC);
225     } else {
226       sorting = spaceFilter.getSorting();
227     }
228 
229     //
230     Ordering ordering = Ordering.valueOf(sorting.orderBy.toString());
231     switch (sorting.sortBy) {
232       case DATE:
233         builder.orderBy(SpaceEntity.createdTime.getName(), ordering);
234         break;
235       case RELEVANCY:
236         builder.orderBy(JCRProperties.JCR_RELEVANCY.getName(), ordering);
237       case TITLE:
238         builder.orderBy(SpaceEntity.name.getName(), ordering);
239         break;
240     }
241   }
242 
243   /**
244    * The reference types.
245    */
246   public enum RefType {
247     MEMBER() {
248       @Override
249       public SpaceListEntity refsOf(IdentityEntity identityEntity) {
250         return identityEntity.getSpaces();
251       }
252       @Override
253       public String[] idsOf(Space space) {
254         return space.getMembers();
255       }
256       @Override
257       public void setIds(Space space, String[] ids) {
258         space.setMembers(ids);
259       }
260     },
261     MANAGER() {
262       @Override
263       public SpaceListEntity refsOf(IdentityEntity identityEntity) {
264         return identityEntity.getManagerSpaces();
265       }
266       @Override
267       public String[] idsOf(Space space) {
268         return space.getManagers();
269       }
270       @Override
271       public void setIds(Space space, String[] ids) {
272         space.setManagers(ids);
273       }
274     },
275     PENDING() {
276       @Override
277       public SpaceListEntity refsOf(IdentityEntity identityEntity) {
278         return identityEntity.getPendingSpaces();
279       }
280       @Override
281       public String[] idsOf(Space space) {
282         return space.getPendingUsers();
283       }
284       @Override
285       public void setIds(Space space, String[] ids) {
286         space.setPendingUsers(ids);
287       }
288     },
289     INVITED() {
290       @Override
291       public SpaceListEntity refsOf(IdentityEntity identityEntity) {
292         return identityEntity.getInvitedSpaces();
293       }
294       @Override
295       public String[] idsOf(Space space) {
296         return space.getInvitedUsers();
297       }
298       @Override
299       public void setIds(Space space, String[] ids) {
300         space.setInvitedUsers(ids);
301       }
302     };
303 
304     public abstract SpaceListEntity refsOf(IdentityEntity identityEntity);
305     public abstract String[] idsOf(Space space);
306     public abstract void setIds(Space space, String[] ids);
307   }
308 
309   private class UpdateContext {
310     private String[] added;
311     private String[] removed;
312 
313     private UpdateContext(String[] added, String[] removed) {
314       this.added = added;
315       this.removed = removed;
316     }
317 
318     public String[] getAdded() {
319       return added;
320     }
321 
322     public String[] getRemoved() {
323       return removed;
324     }
325   }
326 
327   private String[] sub(String[] l1, String[] l2) {
328 
329     if (l1 == null) {
330       return new String[]{};
331     }
332 
333     if (l2 == null) {
334       return l1;
335     }
336 
337     List<String> l = new ArrayList(Arrays.asList(l1));
338     l.removeAll(Arrays.asList(l2));
339     return l.toArray(new String[]{});
340   }
341 
342   private void createRefs(SpaceEntity spaceEntity, Space space) throws NodeNotFoundException {
343 
344     String[] removedMembers = sub(spaceEntity.getMembersId(), space.getMembers());
345     String[] removedManagers = sub(spaceEntity.getManagerMembersId(), space.getManagers());
346     String[] removedInvited = sub(spaceEntity.getInvitedMembersId(), space.getInvitedUsers());
347     String[] removedPending = sub(spaceEntity.getPendingMembersId(), space.getPendingUsers());
348 
349     String[] addedMembers = sub(space.getMembers(), spaceEntity.getMembersId());
350     String[] addedManagers = sub(space.getManagers(), spaceEntity.getManagerMembersId());
351     String[] addedInvited = sub(space.getInvitedUsers(), spaceEntity.getInvitedMembersId());
352     String[] addedPending = sub(space.getPendingUsers(), spaceEntity.getPendingMembersId());
353 
354     manageRefList(new UpdateContext(addedMembers, removedMembers), spaceEntity, RefType.MEMBER);
355     manageActivityRefList(new UpdateContext(addedMembers, removedMembers), spaceEntity, RefType.MEMBER);
356     
357     manageRefList(new UpdateContext(addedManagers, removedManagers), spaceEntity, RefType.MANAGER);
358     manageRefList(new UpdateContext(addedInvited, removedInvited), spaceEntity, RefType.INVITED);
359     manageRefList(new UpdateContext(addedPending, removedPending), spaceEntity, RefType.PENDING);
360 
361   }
362 
363   private void changeSpaceRef(SpaceEntity spaceEntity, Space space, RefType type) {
364     String []listUserNames = null;
365     
366     if (RefType.MEMBER.equals(type)) {
367       listUserNames = spaceEntity.getMembersId();
368     } else if (RefType.MANAGER.equals(type)) {
369       listUserNames = spaceEntity.getManagerMembersId();
370     } else if (RefType.INVITED.equals(type)) {
371       listUserNames = spaceEntity.getInvitedMembersId();
372     } else {
373       listUserNames = spaceEntity.getPendingMembersId();
374     }
375     
376     if (listUserNames != null) {
377       for (String userName : listUserNames) {
378         try {
379           IdentityEntity identityEntity = identityStorage._findIdentityEntity(OrganizationIdentityProvider.NAME, userName);
380           SpaceListEntity listRef = type.refsOf(identityEntity);
381           SpaceRef ref = listRef.getRef(spaceEntity.getName());
382           ref.setName(space.getPrettyName());
383         } catch (NodeNotFoundException e) {
384           LOG.warn(e.getMessage(), e);
385         }
386       }
387     }
388   }
389   
390   private void changeSpaceRef(String remoteId, SpaceEntity spaceEntity, Space space, RefType type) {
391     try {
392       IdentityEntity identityEntity = identityStorage._findIdentityEntity(OrganizationIdentityProvider.NAME, remoteId);
393       SpaceListEntity listRef = type.refsOf(identityEntity);
394       SpaceRef ref = listRef.getRef(spaceEntity.getName());
395       ref.setName(space.getPrettyName());
396     } catch (NodeNotFoundException e) {
397       LOG.warn(e.getMessage(), e);
398     }
399   }
400   
401   private void manageRefList(UpdateContext context, SpaceEntity spaceEntity, RefType type) {
402 
403     if (context.getAdded() != null) {
404       for (String userName : context.getAdded()) {
405         try {
406           IdentityEntity identityEntity = identityStorage._findIdentityEntity(OrganizationIdentityProvider.NAME, userName);
407           SpaceListEntity listRef = type.refsOf(identityEntity);
408           SpaceRef ref = listRef.getRef(spaceEntity.getName());
409           if (!ref.getName().equals(spaceEntity.getName())) {
410             ref.setName(spaceEntity.getName());
411           }
412           ref.setSpaceRef(spaceEntity);
413         }
414         catch (NodeNotFoundException e) {
415           LOG.warn(e.getMessage(), e);
416         }
417       }
418 
419       for (String userName : context.getRemoved()) {
420         try {
421           IdentityEntity identityEntity = identityStorage._findIdentityEntity(OrganizationIdentityProvider.NAME, userName);
422           SpaceListEntity listRef = type.refsOf(identityEntity);
423           SpaceRef ref = listRef.getRef(spaceEntity.getName());
424           getSession().remove(ref);
425         }
426         catch (NodeNotFoundException e) {
427           LOG.warn(e.getMessage(), e);
428         }
429       }
430     }
431   }
432   
433   private void manageActivityRefList(UpdateContext context, SpaceEntity spaceEntity, RefType type) {
434 
435     Identity spaceIdentity = identityStorage.findIdentity(SpaceIdentityProvider.NAME,
436                                                           spaceEntity.getPrettyName());
437     if (context.getAdded() != null) {
438       for (String userName : context.getAdded()) {
439         Identity identity = identityStorage.findIdentity(OrganizationIdentityProvider.NAME, userName);
440         //streamStorage.addSpaceMember(identity, spaceIdentity);
441         StreamInvocationHelper.addSpaceMember(identity, spaceIdentity);
442       }
443     }
444 
445     if (context.getRemoved() != null) {
446       for (String userName : context.getRemoved()) {
447         Identity identity = identityStorage.findIdentity(OrganizationIdentityProvider.NAME, userName);
448         //streamStorage.removeSpaceMember(identity, spaceIdentity);
449         StreamInvocationHelper.removeSpaceMember(identity, spaceIdentity);
450       }
451     }
452   }
453 
454   private boolean validateFilter(SpaceFilter filter) {
455     if (filter == null) {
456       return false;
457     }
458 
459     if (filter.getSpaceNameSearchCondition() != null &&
460         filter.getSpaceNameSearchCondition().length() != 0) {
461       return isValidInput(filter.getSpaceNameSearchCondition());
462     }
463     else if (!Character.isDigit(filter.getFirstCharacterOfSpaceName())) {
464       return true;
465     }
466     return false;
467 
468   }
469 
470   private SpaceEntity createSpace(Space space) throws SpaceStorageException {
471 
472     SpaceRootEntity spaceRootEntity = getSpaceRoot();
473     SpaceEntity spaceEntity = spaceRootEntity.getSpace(space.getPrettyName());
474     space.setId(spaceEntity.getId());
475 
476     return spaceEntity;
477 
478   }
479 
480   private SpaceEntity _saveSpace(Space space) throws NodeNotFoundException {
481 
482     return _findById(SpaceEntity.class, space.getId());
483 
484   }
485 
486   private void _applyFilter(WhereExpression whereExpression, SpaceFilter spaceFilter) {
487 
488     String spaceNameSearchCondition = spaceFilter.getSpaceNameSearchCondition();
489     char firstCharacterOfName = spaceFilter.getFirstCharacterOfSpaceName();
490 
491     if (spaceNameSearchCondition != null && spaceNameSearchCondition.length() != 0) {
492       if (this.isValidInput(spaceNameSearchCondition)) {
493 
494         spaceNameSearchCondition = new StringBuilder().append(StorageUtils.PERCENT_STR)
495             .append(spaceNameSearchCondition.replace(StorageUtils.ASTERISK_STR, StorageUtils.PERCENT_STR).toLowerCase()).append(StorageUtils.PERCENT_STR).toString();
496 
497         whereExpression.startGroup();
498         whereExpression
499             .like(whereExpression.callFunction(QueryFunction.LOWER, SpaceEntity.name), spaceNameSearchCondition)
500             .or()
501             .like(whereExpression.callFunction(QueryFunction.LOWER, SpaceEntity.displayName), spaceNameSearchCondition)
502             .or()
503             .like(whereExpression.callFunction(QueryFunction.LOWER, SpaceEntity.description), StringEscapeUtils.escapeHtml(spaceNameSearchCondition));
504         whereExpression.endGroup();
505 
506         List<Space> exclusions = spaceFilter.getExclusions();
507         if (exclusions != null) {
508           for (Space space : exclusions) {
509             whereExpression.and().not().equals(SpaceEntity.name, space.getPrettyName());
510           }
511         }
512       }
513     }
514     else if (!Character.isDigit(firstCharacterOfName)) {
515       String firstCharacterOfNameString = Character.toString(firstCharacterOfName);
516       String firstCharacterOfNameLowerCase = firstCharacterOfNameString.toLowerCase() + StorageUtils.PERCENT_STR;
517       whereExpression
518           .like(whereExpression.callFunction(QueryFunction.LOWER, SpaceEntity.name), firstCharacterOfNameLowerCase);
519     }
520   }
521   
522   private boolean isValidInput(String input) {
523     if (input == null || input.length() == 0) {
524       return false;
525     }
526     String cleanString = input.replaceAll("\\*", "");
527     cleanString = cleanString.replaceAll("\\%", "");
528     if (cleanString.length() == 0) {
529        return false;
530     }
531     return true;
532   }
533 
534   private List<String> processUnifiedSearchCondition(String searchCondition) {
535     String[] spaceConditions = searchCondition.split(" ");
536     List<String> result = new ArrayList<String>(spaceConditions.length);
537     for (String conditionValue : spaceConditions) {
538       result.add(conditionValue.toString());
539     }
540     return result;
541   }
542 
543   /*
544     Filter query
545    */
546 
547   private Query<SpaceEntity> _getSpacesByFilterQuery(String userId, SpaceFilter spaceFilter) {
548 
549     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
550     WhereExpression whereExpression = new WhereExpression();
551 
552     if (validateFilter(spaceFilter)) {
553       _applyFilter(whereExpression, spaceFilter);
554     }
555 
556     if (userId != null && validateFilter(spaceFilter)) {
557       whereExpression
558           .and()
559           .equals(SpaceEntity.membersId, userId);
560     } else if (userId != null && !validateFilter(spaceFilter)) {
561       whereExpression
562           .equals(SpaceEntity.membersId, userId);
563     }
564 
565     if (whereExpression.toString().length() > 0) {
566       builder.where(whereExpression.toString());
567     }
568 
569     applyOrder(builder, spaceFilter);
570 
571     return builder.get();
572 
573   }
574 
575   private Query<SpaceEntity> getAllSpacesQuery(SpaceFilter spaceFilter) {
576     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
577     WhereExpression whereExpression = new WhereExpression();
578 
579     if (validateFilter(spaceFilter)) {
580       _applyFilter(whereExpression, spaceFilter);
581       whereExpression.and();
582       whereExpression.startGroup();
583     }
584 
585     if (whereExpression.toString().length() > 0) {
586       builder.where(whereExpression.toString());
587     }
588 
589     applyOrder(builder, spaceFilter);
590 
591     return builder.get();
592     
593   }
594   
595   private Query<SpaceEntity> getAccessibleSpacesByFilterQuery(String userId, SpaceFilter spaceFilter) {
596 
597     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
598     WhereExpression whereExpression = new WhereExpression();
599 
600     if (validateFilter(spaceFilter)) {
601       _applyFilter(whereExpression, spaceFilter);
602       whereExpression.and();
603       
604       //
605       if (spaceFilter.getAppId() != null) {
606         whereExpression.contains(SpaceEntity.app, spaceFilter.getAppId());
607         whereExpression.and();
608       }
609       
610       //
611       whereExpression.startGroup();
612     } else if (spaceFilter != null && spaceFilter.getAppId() != null) {
613       //
614       whereExpression.contains(SpaceEntity.app, spaceFilter.getAppId());
615       whereExpression.and();
616       
617       //
618       whereExpression.startGroup();
619     }
620 
621     whereExpression
622         .equals(SpaceEntity.membersId, userId)
623         .or()
624         .equals(SpaceEntity.managerMembersId, userId);
625 
626     whereExpression.endAllGroup();
627 
628     if (whereExpression.toString().length() > 0) {
629       builder.where(whereExpression.toString());
630     }
631 
632     applyOrder(builder, spaceFilter);
633 
634     return builder.get();
635 
636   }
637 
638   private Query<SpaceEntity> getPublicSpacesQuery(String userId) {
639     return getPublicSpacesQuery(userId, null);
640   }
641 
642   private Query<SpaceEntity> getPublicSpacesQuery(String userId, SpaceFilter spaceFilter) {
643 
644     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
645     WhereExpression whereExpression = new WhereExpression();
646 
647     if (validateFilter(spaceFilter)) {
648       _applyFilter(whereExpression, spaceFilter);
649       whereExpression.and();
650     }
651 
652     builder.where(whereExpression
653         .not().equals(SpaceEntity.membersId, userId)
654         .and().not().equals(SpaceEntity.managerMembersId, userId)
655         .and().not().equals(SpaceEntity.invitedMembersId, userId)
656         .and().not().equals(SpaceEntity.pendingMembersId, userId)
657         .toString()
658     );
659 
660     if (whereExpression.toString().length() > 0) {
661       builder.where(whereExpression.toString());
662     }
663 
664     applyOrder(builder, spaceFilter);
665 
666     return builder.get();
667 
668   }
669   
670   private Query<SpaceEntity> getPublicSpacesOfMemberQuery(String userId) {
671 
672     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
673     WhereExpression whereExpression = new WhereExpression();
674     
675     builder.where(whereExpression
676         .equals(SpaceEntity.membersId, userId)
677         .and().equals(SpaceEntity.visibility, Space.PUBLIC)
678         .and().not().equals(SpaceEntity.managerMembersId, userId)
679         .and().not().equals(SpaceEntity.invitedMembersId, userId)
680         .and().not().equals(SpaceEntity.pendingMembersId, userId)
681         .toString()
682     );
683 
684     if (whereExpression.toString().length() > 0) {
685       builder.where(whereExpression.toString());
686     }
687 
688     builder.orderBy(SpaceEntity.name.getName(), Ordering.ASC);
689 
690     return builder.get();
691 
692   }
693 
694   private Query<SpaceEntity> getSpacesOfMemberQuery(String userId) {
695 
696     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
697     WhereExpression whereExpression = new WhereExpression();
698     
699     builder.where(whereExpression
700         .equals(SpaceEntity.membersId, userId)
701         .and().not().equals(SpaceEntity.visibility, Space.HIDDEN)
702         .and().not().equals(SpaceEntity.invitedMembersId, userId)
703         .and().not().equals(SpaceEntity.pendingMembersId, userId)
704         .toString()
705     );
706 
707     if (whereExpression.toString().length() > 0) {
708       builder.where(whereExpression.toString());
709     }
710 
711     builder.orderBy(SpaceEntity.name.getName(), Ordering.ASC);
712 
713     return builder.get();
714 
715   }
716   
717   private Query<SpaceEntity> getPendingSpacesFilterQuery(String userId, SpaceFilter spaceFilter) {
718 
719     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
720     WhereExpression whereExpression = new WhereExpression();
721 
722     if (validateFilter(spaceFilter)) {
723       _applyFilter(whereExpression, spaceFilter);
724       whereExpression.and();
725     }
726 
727     builder.where(whereExpression
728         .equals(SpaceEntity.pendingMembersId, userId)
729         .toString()
730     );
731 
732     if (whereExpression.toString().length() > 0) {
733       builder.where(whereExpression.toString());
734     }
735 
736     applyOrder(builder, spaceFilter);
737 
738     return builder.get();
739 
740   }
741 
742   private Query<SpaceEntity> getInvitedSpacesFilterQuery(String userId, SpaceFilter spaceFilter) {
743 
744     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
745     WhereExpression whereExpression = new WhereExpression();
746 
747     if (validateFilter(spaceFilter)) {
748       _applyFilter(whereExpression, spaceFilter);
749       whereExpression.and();
750     }
751 
752     builder.where(whereExpression
753         .equals(SpaceEntity.invitedMembersId, userId)
754         .toString()
755     );
756 
757     if (whereExpression.toString().length() > 0) {
758       builder.where(whereExpression.toString());
759     }
760 
761     applyOrder(builder, spaceFilter);
762 
763     return builder.get();
764 
765   }
766 
767   private Query<SpaceEntity> getEditableSpacesFilterQuery(String userId, SpaceFilter spaceFilter) {
768 
769     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
770     WhereExpression whereExpression = new WhereExpression();
771 
772     if (validateFilter(spaceFilter)) {
773       _applyFilter(whereExpression, spaceFilter);
774       whereExpression.and();
775     }
776 
777     builder.where(whereExpression
778         .equals(SpaceEntity.managerMembersId, userId)
779         .toString()
780     );
781 
782     if (whereExpression.toString().length() > 0) {
783       builder.where(whereExpression.toString());
784     }
785     
786     applyOrder(builder, spaceFilter);
787 
788     return builder.get();
789 
790   }
791 
792   private Query<SpaceEntity> getSpacesByFilterQuery(SpaceFilter spaceFilter) {
793     return _getSpacesByFilterQuery(null, spaceFilter);
794   }
795 
796   /*
797     Public
798    */
799 
800   /**
801    * {@inheritDoc}
802    */
803   public Space getSpaceByDisplayName(String spaceDisplayName) throws SpaceStorageException {
804     Space space = null;
805 
806     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
807     WhereExpression whereExpression = new WhereExpression();
808 
809     whereExpression.equals(SpaceEntity.displayName, spaceDisplayName);
810 
811     QueryResult<SpaceEntity> result = builder.where(whereExpression.toString()).get().objects();
812     
813     if (result.hasNext()) {
814       space = new Space();
815       fillSpaceFromEntity(result.next(), space);
816     }
817 
818     return space;
819   }
820 
821   /**
822    * {@inheritDoc}
823    */
824   public void saveSpace(Space space, boolean isNew) throws SpaceStorageException {
825 
826     SpaceEntity entity;
827 
828     try {
829       
830       if (isNew) {
831         entity = createSpace(space);
832       }
833       else {
834         entity = _saveSpace(space);
835       }
836 
837       //
838       createRefs(entity, space);
839       
840       fillEntityFromSpace(space, entity);
841       
842       if (!isNew) {
843         getSession().save();
844       }
845       
846       LOG.debug(String.format(
847           "Space %s (%s) saved",
848           space.getPrettyName(),
849           space.getId()
850       ));
851 
852     }
853     catch (NodeNotFoundException e) {
854       throw new SpaceStorageException(SpaceStorageException.Type.FAILED_TO_SAVE_SPACE, e.getMessage(), e);
855     }
856 
857   }
858 
859   /**
860    * {@inheritDoc}
861    */
862   public void renameSpace(Space space, String newDisplayName) {
863     renameSpace(null, space, newDisplayName);
864   }
865   
866   /**
867    * {@inheritDoc}
868    */
869   public void renameSpace(String remoteId, Space space, String newDisplayName) {
870     SpaceEntity entity;
871 
872     try {
873       String oldPrettyName = space.getPrettyName();
874       
875       space.setDisplayName(newDisplayName);
876       space.setPrettyName(space.getDisplayName());
877       space.setUrl(SpaceUtils.cleanString(newDisplayName));
878       
879       entity = _saveSpace(space);
880         
881       //change space ref
882       this.changeSpaceRef(entity, space, RefType.MEMBER);
883       this.changeSpaceRef(entity, space, RefType.MANAGER);
884       this.changeSpaceRef(entity, space, RefType.INVITED);
885       this.changeSpaceRef(entity, space, RefType.PENDING);
886       
887       if (remoteId != null) {
888         this.changeSpaceRef(remoteId, entity, space, RefType.MEMBER);
889       }
890       
891       fillEntityFromSpace(space, entity);
892 
893       //
894       getSession().save();
895 
896       //change profile of space
897       Identity identitySpace = identityStorage.findIdentity(SpaceIdentityProvider.NAME, oldPrettyName);
898       
899       if (identitySpace != null) {
900         Profile profileSpace = identitySpace.getProfile();
901         profileSpace.setProperty(Profile.URL, space.getUrl());
902         
903         identityStorage.saveProfile(profileSpace);
904         
905         identitySpace.setRemoteId(space.getPrettyName());
906         renameIdentity(identitySpace);
907       }
908       
909       //
910       LOG.debug(String.format(
911           "Space %s (%s) saved",
912           space.getPrettyName(),
913           space.getId()
914       ));
915 
916     } catch (NodeNotFoundException e) {
917       throw new SpaceStorageException(SpaceStorageException.Type.FAILED_TO_RENAME_SPACE, e.getMessage(), e);
918     }
919   }
920   
921   /**
922    * Add this method to resolve SOC-3439
923    * @param identity
924    * @throws NodeNotFoundException
925    */
926   private void renameIdentity(Identity identity) throws NodeNotFoundException {
927     ProviderEntity providerEntity = getProviderRoot().getProvider(identity.getProviderId());
928     // Move identity
929     IdentityEntity identityEntity = _findById(IdentityEntity.class, identity.getId());
930     providerEntity.getIdentities().put(identity.getRemoteId(), identityEntity);
931     
932     identityEntity.setRemoteId(identity.getRemoteId());
933   }
934   
935   /**
936    * {@inheritDoc}
937    */
938   public void deleteSpace(String id) throws SpaceStorageException {
939 
940     String name;
941 
942     //
943     try {
944       name = _findById(SpaceEntity.class, id).getPrettyName();
945     }
946     catch (NodeNotFoundException e) {
947       throw new SpaceStorageException(SpaceStorageException.Type.FAILED_TO_DELETE_SPACE, e.getMessage());
948     }
949 
950     //
951     _removeById(SpaceEntity.class, id);
952 
953     //
954     getSession().save();
955 
956     //
957     LOG.debug(String.format(
958         "Space %s removed",
959         name)
960     );
961   }
962 
963   /**
964    * {@inheritDoc}
965    */
966   @Override
967   public void ignoreSpace(String spaceId, String userId) {
968     return;
969   }
970 
971   /**
972    * {@inheritDoc}
973    */
974   @Override
975   public boolean isSpaceIgnored(String spaceId, String userId) {
976     return false;
977   }
978 
979   /*
980     Member spaces
981    */
982 
983   /**
984    * {@inheritDoc}
985    */
986   public int getMemberSpacesCount(String userId) throws SpaceStorageException {
987     try {
988        return identityStorage._findIdentityEntity(OrganizationIdentityProvider.NAME, userId).getSpaces().getRefs().size();
989     }
990     catch (NodeNotFoundException e){
991        return 0;
992     }
993   }
994 
995   /**
996    * {@inheritDoc}
997    */
998   public int getMemberSpacesByFilterCount(String userId, SpaceFilter spaceFilter) {
999     return _getSpacesByFilterQuery(userId, spaceFilter).objects().size();
1000   }
1001 
1002   /**
1003    * {@inheritDoc}
1004    */
1005   public List<Space> getMemberSpaces(String userId) throws SpaceStorageException {
1006 
1007     List<Space> spaces = new ArrayList<Space>();
1008 
1009     //
1010     QueryResult<SpaceEntity> results = _getSpacesByFilterQuery(userId, null).objects();
1011 
1012     while (results.hasNext()) {
1013       SpaceEntity currentSpace = results.next();
1014       Space space = new Space();
1015       fillSpaceFromEntity(currentSpace, space);
1016       spaces.add(space);
1017     }
1018 
1019     return spaces;
1020   }
1021 
1022   /**
1023    * {@inheritDoc}
1024    */
1025   public List<Space> getMemberSpaces(String userId, long offset, long limit) throws SpaceStorageException {
1026 
1027     List<Space> spaces = new ArrayList<Space>();
1028 
1029     //
1030     QueryResult<SpaceEntity> results = _getSpacesByFilterQuery(userId, null).objects(offset, limit);
1031 
1032     while (results.hasNext()) {
1033       SpaceEntity currentSpace = results.next();
1034       Space space = new Space();
1035       fillSpaceFromEntity(currentSpace, space);
1036       spaces.add(space);
1037     }
1038 
1039     return spaces;
1040   }
1041 
1042   /**
1043    * {@inheritDoc}
1044    */
1045   public List<Space> getMemberSpacesByFilter(String userId, SpaceFilter spaceFilter, long offset, long limit) {
1046 
1047     List<Space> spaces = new ArrayList<Space>();
1048 
1049     //
1050     QueryResult<SpaceEntity> results = _getSpacesByFilterQuery(userId, spaceFilter).objects(offset, limit);
1051 
1052     while (results.hasNext()) {
1053       SpaceEntity currentSpace = results.next();
1054       Space space = new Space();
1055       fillSpaceFromEntity(currentSpace, space);
1056       spaces.add(space);
1057     }
1058 
1059     return spaces;
1060 
1061   }
1062 
1063   /*
1064     Pending spaces
1065    */
1066 
1067   /**
1068    * {@inheritDoc}
1069    */
1070   public int getPendingSpacesCount(String userId) throws SpaceStorageException {
1071     try {
1072       IdentityEntity identityEntity = identityStorage._findIdentityEntity(OrganizationIdentityProvider.NAME, userId);
1073       Collection<SpaceRef> spaceEntities = identityEntity.getPendingSpaces().getRefs().values();
1074       return spaceEntities.size();
1075     }
1076     catch (NodeNotFoundException e) {
1077       return 0;
1078     }
1079   }
1080 
1081   /**
1082    * {@inheritDoc}
1083    */
1084   public int getPendingSpacesByFilterCount(String userId, SpaceFilter spaceFilter) {
1085     return getPendingSpacesFilterQuery(userId, spaceFilter).objects().size();
1086   }
1087 
1088   /**
1089    * {@inheritDoc}
1090    */
1091   public List<Space> getPendingSpaces(String userId) throws SpaceStorageException {
1092 
1093     List<Space> spaces = new ArrayList<Space>();
1094 
1095     //
1096     QueryResult<SpaceEntity> results = getPendingSpacesFilterQuery(userId, null).objects();
1097 
1098     while (results.hasNext()) {
1099       SpaceEntity currentSpace = results.next();
1100       Space space = new Space();
1101       fillSpaceFromEntity(currentSpace, space);
1102       spaces.add(space);
1103     }
1104 
1105     return spaces;
1106   }
1107 
1108   /**
1109    * {@inheritDoc}
1110    */
1111   public List<Space> getPendingSpaces(String userId, long offset, long limit) throws SpaceStorageException {
1112 
1113     List<Space> spaces = new ArrayList<Space>();
1114 
1115     //
1116     QueryResult<SpaceEntity> results = getPendingSpacesFilterQuery(userId, null).objects(offset, limit);
1117 
1118     while (results.hasNext()) {
1119       SpaceEntity currentSpace = results.next();
1120       Space space = new Space();
1121       fillSpaceFromEntity(currentSpace, space);
1122       spaces.add(space);
1123     }
1124 
1125     return spaces;
1126   }
1127 
1128   /**
1129    * {@inheritDoc}
1130    */
1131   public List<Space> getPendingSpacesByFilter(String userId, SpaceFilter spaceFilter, long offset, long limit) {
1132 
1133     List<Space> spaces = new ArrayList<Space>();
1134 
1135     //
1136     QueryResult<SpaceEntity> results = getPendingSpacesFilterQuery(userId, spaceFilter).objects(offset, limit);
1137 
1138     while (results.hasNext()) {
1139       SpaceEntity currentSpace = results.next();
1140       Space space = new Space();
1141       fillSpaceFromEntity(currentSpace, space);
1142       spaces.add(space);
1143     }
1144 
1145     return spaces;
1146   }
1147 
1148   /*
1149     Invited spaces
1150    */
1151 
1152   /**
1153    * {@inheritDoc}
1154    */
1155   public int getInvitedSpacesCount(String userId) throws SpaceStorageException {
1156 
1157     try {
1158       IdentityEntity identityEntity = identityStorage._findIdentityEntity(OrganizationIdentityProvider.NAME, userId);
1159       Collection<SpaceRef> spaceEntities = identityEntity.getInvitedSpaces().getRefs().values();
1160       return spaceEntities.size();
1161     }
1162     catch (NodeNotFoundException e) {
1163       return 0;
1164     }
1165   }
1166 
1167   /**
1168    * {@inheritDoc}
1169    */
1170   public int getInvitedSpacesByFilterCount(String userId, SpaceFilter spaceFilter) {
1171 
1172     if (validateFilter(spaceFilter)) {
1173       return getInvitedSpacesFilterQuery(userId, spaceFilter).objects().size();
1174     }
1175     else {
1176       return 0;
1177     }
1178   }
1179 
1180   /**
1181    * {@inheritDoc}
1182    */
1183   public List<Space> getInvitedSpaces(String userId) throws SpaceStorageException {
1184 
1185     List<Space> spaces = new ArrayList<Space>();
1186 
1187     //
1188     QueryResult<SpaceEntity> results = getInvitedSpacesFilterQuery(userId, null).objects();
1189 
1190     while (results.hasNext()) {
1191       SpaceEntity currentSpace = results.next();
1192       Space space = new Space();
1193       fillSpaceFromEntity(currentSpace, space);
1194       spaces.add(space);
1195     }
1196 
1197     return spaces;
1198   }
1199 
1200   /**
1201    * {@inheritDoc}
1202    */
1203   public List<Space> getInvitedSpaces(String userId, long offset, long limit) throws SpaceStorageException {
1204     
1205     List<Space> spaces = new ArrayList<Space>();
1206 
1207     //
1208     QueryResult<SpaceEntity> results = getInvitedSpacesFilterQuery(userId, null).objects(offset, limit);
1209 
1210     while (results.hasNext()) {
1211       SpaceEntity currentSpace = results.next();
1212       Space space = new Space();
1213       fillSpaceFromEntity(currentSpace, space);
1214       spaces.add(space);
1215     }
1216 
1217     return spaces;
1218   }
1219 
1220   /**
1221    * {@inheritDoc}
1222    */
1223   public List<Space> getInvitedSpacesByFilter(String userId, SpaceFilter spaceFilter, long offset, long limit) {
1224 
1225     List<Space> spaces = new ArrayList<Space>();
1226 
1227     //
1228     QueryResult<SpaceEntity> results = getInvitedSpacesFilterQuery(userId, spaceFilter).objects(offset, limit);
1229 
1230     while (results.hasNext()) {
1231       SpaceEntity currentSpace = results.next();
1232       Space space = new Space();
1233       fillSpaceFromEntity(currentSpace, space);
1234       spaces.add(space);
1235     }
1236 
1237     return spaces;
1238   }
1239 
1240   /*
1241     Public spaces
1242    */
1243 
1244   /**
1245    * {@inheritDoc}
1246    */
1247   public int getPublicSpacesCount(String userId) throws SpaceStorageException {
1248     return getPublicSpacesQuery(userId).objects().size();
1249   }
1250 
1251   /**
1252    * {@inheritDoc}
1253    */
1254   public int getPublicSpacesByFilterCount(String userId, SpaceFilter spaceFilter) {
1255     if (validateFilter(spaceFilter)) {
1256       return getPublicSpacesQuery(userId, spaceFilter).objects().size();
1257     }
1258     else {
1259       return 0;
1260     }
1261   }
1262 
1263   /**
1264    * {@inheritDoc}
1265    */
1266   public List<Space> getPublicSpacesByFilter(String userId, SpaceFilter spaceFilter, long offset, long limit) {
1267 
1268     try {
1269       identityStorage._findIdentityEntity(OrganizationIdentityProvider.NAME, userId);
1270     }
1271     catch (NodeNotFoundException e) {
1272       userId = null;
1273     }
1274 
1275     List<Space> spaces = new ArrayList<Space>();
1276 
1277     //
1278     QueryResult<SpaceEntity> results = getPublicSpacesQuery(userId, spaceFilter).objects(offset, limit);
1279 
1280     while (results.hasNext()) {
1281       SpaceEntity currentSpace = results.next();
1282       Space space = new Space();
1283       fillSpaceFromEntity(currentSpace, space);
1284       spaces.add(space);
1285     }
1286 
1287     return spaces;
1288   }
1289 
1290   /**
1291    * {@inheritDoc}
1292    */
1293   public List<Space> getPublicSpaces(String userId) throws SpaceStorageException {
1294     List<Space> spaces = new ArrayList<Space>();
1295 
1296     //
1297     QueryResult<SpaceEntity> results = getPublicSpacesQuery(userId).objects();
1298 
1299     while (results.hasNext()) {
1300       SpaceEntity currentSpace = results.next();
1301       Space space = new Space();
1302       fillSpaceFromEntity(currentSpace, space);
1303       spaces.add(space);
1304     }
1305 
1306     return spaces;
1307   }
1308 
1309   /**
1310    * {@inheritDoc}
1311    */
1312   public List<Space> getPublicSpaces(String userId, long offset, long limit) throws SpaceStorageException {
1313 
1314     List<Space> spaces = new ArrayList<Space>();
1315 
1316     //
1317     QueryResult<SpaceEntity> results = getPublicSpacesQuery(userId).objects(offset, limit);
1318 
1319     while (results.hasNext()) {
1320       SpaceEntity currentSpace = results.next();
1321       Space space = new Space();
1322       fillSpaceFromEntity(currentSpace, space);
1323       spaces.add(space);
1324     }
1325 
1326     return spaces;
1327   }
1328   
1329   
1330   /*
1331     Accessible spaces
1332    */
1333   /**
1334    * {@inheritDoc}
1335    */
1336   public int getAccessibleSpacesCount(String userId) throws SpaceStorageException {
1337     return getAccessibleSpacesByFilterQuery(userId, null).objects().size();
1338   }
1339 
1340   /**
1341    * {@inheritDoc}
1342    */
1343   public int getAccessibleSpacesByFilterCount(String userId, SpaceFilter spaceFilter) {
1344     return getAccessibleSpacesByFilterQuery(userId, spaceFilter).objects().size();
1345   }
1346   
1347   /**
1348    * {@inheritDoc}
1349    */
1350   public int getLastAccessedSpaceCount(SpaceFilter filter) {
1351     
1352     try {
1353       IdentityEntity identityEntity = identityStorage._findIdentityEntity(OrganizationIdentityProvider.NAME, filter.getRemoteId());
1354       SpaceListEntity listRef = RefType.MEMBER.refsOf(identityEntity);
1355       Map<String, SpaceRef> mapRefs = listRef.getRefs();
1356       //
1357       int counter = 0;
1358       
1359       //
1360       for(Map.Entry<String, SpaceRef> entry :  mapRefs.entrySet()) {
1361         SpaceRef ref = entry.getValue();
1362 
1363         // Lazy clean up
1364         if (ref.getSpaceRef() == null) {
1365           listRef.removeRef(entry.getKey());
1366           continue;
1367         }
1368 
1369         if (filter.getAppId() == null) {
1370           counter++;
1371         } else {
1372           if (ref.getSpaceRef().getApp().toLowerCase().indexOf(filter.getAppId().toLowerCase()) > 0) {
1373             counter++;
1374           }
1375         }
1376       }
1377 
1378       
1379       
1380       return counter;
1381       } catch (NodeNotFoundException e) {
1382         LOG.warn(e.getMessage(), e);
1383         return 0;
1384       }
1385   }
1386 
1387   /**
1388    * {@inheritDoc}
1389    */
1390   public List<Space> getAccessibleSpaces(String userId) throws SpaceStorageException {
1391 
1392     List<Space> spaces = new ArrayList<Space>();
1393 
1394     //
1395     QueryResult<SpaceEntity> results = getAccessibleSpacesByFilterQuery(userId, null).objects();
1396 
1397     while (results.hasNext()) {
1398       SpaceEntity currentSpace = results.next();
1399       Space space = new Space();
1400       fillSpaceFromEntity(currentSpace, space);
1401       spaces.add(space);
1402     }
1403 
1404     return spaces;
1405   }
1406   
1407   /*
1408    * Visible spaces
1409    */
1410 
1411   /**
1412    * {@inheritDoc}
1413    */
1414   public int getVisibleSpacesCount(String userId, SpaceFilter spaceFilter) throws SpaceStorageException {
1415     return _getVisibleSpaces(userId, spaceFilter).objects().size();
1416   }
1417   
1418   /**
1419    * {@inheritDoc}
1420    */
1421   public int getUnifiedSearchSpacesCount(String userId, SpaceFilter spaceFilter) throws SpaceStorageException {
1422     return _getUnifiedSearchSpaces(userId, spaceFilter).objects().size();
1423   }
1424 
1425   
1426   /**
1427    * {@inheritDoc}
1428    */
1429   public List<Space> getVisibleSpaces(String userId, SpaceFilter spaceFilter) throws SpaceStorageException {
1430 
1431     List<Space> spaces = new ArrayList<Space>();
1432 
1433     //
1434     QueryResult<SpaceEntity> results = _getVisibleSpaces(userId, spaceFilter).objects();
1435 
1436     while (results.hasNext()) {
1437       SpaceEntity currentSpace = results.next();
1438       Space space = new Space();
1439       fillSpaceFromEntity(currentSpace, space);
1440       spaces.add(space);
1441     }
1442 
1443     return spaces;
1444   }
1445   
1446   /**
1447    * {@inheritDoc}
1448    */
1449   public List<Space> getVisibleSpaces(String userId, SpaceFilter spaceFilter, long offset, long limit)
1450                                       throws SpaceStorageException {
1451     List<Space> spaces = new ArrayList<Space>();
1452 
1453     //
1454     QueryResult<SpaceEntity> results = _getVisibleSpaces(userId, spaceFilter).objects(offset, limit);
1455 
1456     while (results.hasNext()) {
1457       SpaceEntity currentSpace = results.next();
1458       Space space = new Space();
1459       fillSpaceFromEntity(currentSpace, space);
1460       spaces.add(space);
1461     }
1462 
1463     return spaces;
1464   }
1465   
1466   /**
1467    * {@inheritDoc}
1468    */
1469   public List<Space> getUnifiedSearchSpaces(String userId, SpaceFilter spaceFilter, long offset, long limit)
1470                                       throws SpaceStorageException {
1471     List<Space> spaces = new ArrayList<Space>();
1472     
1473     //
1474     QueryResult<SpaceEntity> results = _getUnifiedSearchSpaces(userId, spaceFilter).objects(offset, limit);
1475 
1476     while (results.hasNext()) {
1477       SpaceEntity currentSpace = results.next();
1478       Space space = new Space();
1479       fillSpaceFromEntity(currentSpace, space);
1480       spaces.add(space);
1481     }
1482 
1483     return spaces;
1484   }
1485   
1486   private Query<SpaceEntity> _getUnifiedSearchSpaces(String userId, SpaceFilter spaceFilter) {
1487     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
1488     WhereExpression whereExpression = new WhereExpression();
1489 
1490     _applyUnifiedSearchFilter(whereExpression, spaceFilter);
1491 
1492     if (whereExpression.toString().trim().length() > 0) {
1493       builder.where(whereExpression.toString());
1494     }
1495     applyOrder(builder, spaceFilter);
1496     
1497     return builder.get();
1498   }
1499   
1500   private void _applyUnifiedSearchFilter(WhereExpression whereExpression, SpaceFilter spaceFilter) {
1501 
1502     if (spaceFilter == null) return;
1503 
1504     String spaceNameSearchCondition = StorageUtils.escapeSpecialCharacter(spaceFilter.getSpaceNameSearchCondition());
1505 
1506     char firstCharacterOfName = spaceFilter.getFirstCharacterOfSpaceName();
1507 
1508     if (spaceNameSearchCondition != null && spaceNameSearchCondition.length() != 0) {
1509 
1510         List<String> unifiedSearchConditions = this.processUnifiedSearchCondition(spaceNameSearchCondition);
1511         
1512         if (unifiedSearchConditions.size() > 0) {
1513           whereExpression.startGroup();
1514         }
1515         
1516         boolean first = true;
1517         for(String condition : unifiedSearchConditions) {
1518           //
1519           if (first == false) {
1520             whereExpression.and();
1521           }
1522           whereExpression.startGroup();
1523           whereExpression
1524              .contains(SpaceEntity.name, condition.toLowerCase())
1525              .or()
1526              .contains(SpaceEntity.displayName, condition.toLowerCase())
1527              .or()
1528              .contains(SpaceEntity.description, StringEscapeUtils.escapeHtml(condition).toLowerCase());
1529           whereExpression.endGroup();
1530           
1531           first = false;
1532         } //end for
1533         
1534         if (unifiedSearchConditions.size() > 0) {
1535           whereExpression.endGroup();
1536         }
1537     }
1538     else if (!Character.isDigit(firstCharacterOfName)) {
1539       String firstCharacterOfNameString = Character.toString(firstCharacterOfName);
1540       String firstCharacterOfNameLowerCase = firstCharacterOfNameString.toLowerCase() + StorageUtils.PERCENT_STR;
1541       whereExpression
1542           .like(whereExpression.callFunction(QueryFunction.LOWER, SpaceEntity.name), firstCharacterOfNameLowerCase);
1543     }
1544   }
1545 
1546   private Query<SpaceEntity> _getVisibleSpaces(String userId, SpaceFilter spaceFilter) {
1547 
1548     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
1549     WhereExpression whereExpression = new WhereExpression();
1550 
1551     if (validateFilter(spaceFilter)) {
1552       _applyFilter(whereExpression, spaceFilter);
1553       whereExpression.and();
1554       whereExpression.startGroup();
1555     }
1556     
1557     //visibility::(soc:visibily like 'private') 
1558     whereExpression.startGroup();
1559     whereExpression.like(SpaceEntity.visibility, Space.PRIVATE);
1560     whereExpression.endGroup();
1561     
1562     //(soc:visibily like 'private' AND (soc:registration like 'open' OR soc:registration like 'validate'))
1563     // OR
1564     //(soc:membersId like '' OR managerMembersId like '' OR soc:invitedMembersId like '')
1565     whereExpression.or(); 
1566     whereExpression.startGroup(); 
1567 
1568     whereExpression.equals(SpaceEntity.membersId, userId)
1569                    .or()
1570                    .equals(SpaceEntity.managerMembersId, userId)
1571                    .or()
1572                    .equals(SpaceEntity.invitedMembersId, userId);
1573 
1574     whereExpression.endGroup();
1575     whereExpression.endAllGroup();
1576 
1577 
1578     builder.where(whereExpression.toString());
1579     applyOrder(builder, spaceFilter);
1580     
1581     return builder.get();
1582 
1583   }
1584 
1585 
1586   /**
1587    * {@inheritDoc}
1588    */
1589   public List<Space> getAccessibleSpaces(String userId, long offset, long limit) throws SpaceStorageException {
1590     List<Space> spaces = new ArrayList<Space>();
1591 
1592     //
1593     QueryResult<SpaceEntity> results = getAccessibleSpacesByFilterQuery(userId, null).objects(offset, limit);
1594 
1595     while (results.hasNext()) {
1596       SpaceEntity currentSpace = results.next();
1597       Space space = new Space();
1598       fillSpaceFromEntity(currentSpace, space);
1599       spaces.add(space);
1600     }
1601 
1602     return spaces;
1603   }
1604 
1605   /**
1606    * {@inheritDoc}
1607    */
1608   public List<Space> getAccessibleSpacesByFilter(String userId, SpaceFilter spaceFilter, long offset, long limit) {
1609 
1610     List<Space> spaces = new ArrayList<Space>();
1611 
1612     //
1613     QueryResult<SpaceEntity> results = getAccessibleSpacesByFilterQuery(userId, spaceFilter).objects(offset, limit);
1614 
1615     while (results.hasNext()) {
1616       SpaceEntity currentSpace = results.next();
1617       Space space = new Space();
1618       fillSpaceFromEntity(currentSpace, space);
1619       spaces.add(space);
1620     }
1621 
1622     return spaces;
1623   }
1624 
1625   /*
1626     Editable spaces
1627    */
1628 
1629   /**
1630    * {@inheritDoc}
1631    */
1632   public int getEditableSpacesCount(String userId) throws SpaceStorageException {
1633     try {
1634       IdentityEntity identityEntity = identityStorage._findIdentityEntity(OrganizationIdentityProvider.NAME, userId);
1635       return identityEntity.getManagerSpaces().getRefs().size();
1636     }
1637     catch (NodeNotFoundException e) {
1638       return 0;
1639     }
1640   }
1641 
1642   /**
1643    * {@inheritDoc}
1644    */
1645   public int getEditableSpacesByFilterCount(String userId, SpaceFilter spaceFilter) {
1646     return getEditableSpacesFilterQuery(userId, spaceFilter).objects().size();
1647   }
1648 
1649   /**
1650    * {@inheritDoc}
1651    */
1652   public List<Space> getEditableSpaces(String userId) throws SpaceStorageException {
1653 
1654     List<Space> spaces = new ArrayList<Space>();
1655 
1656     //
1657     QueryResult<SpaceEntity> results = getEditableSpacesFilterQuery(userId, null).objects();
1658 
1659     while (results.hasNext()) {
1660       SpaceEntity currentSpace = results.next();
1661       Space space = new Space();
1662       fillSpaceFromEntity(currentSpace, space);
1663       spaces.add(space);
1664     }
1665 
1666     return spaces;
1667   }
1668 
1669   /**
1670    * {@inheritDoc}
1671    */
1672   public List<Space> getEditableSpaces(String userId, long offset, long limit) throws SpaceStorageException {
1673 
1674     List<Space> spaces = new ArrayList<Space>();
1675 
1676     //
1677     QueryResult<SpaceEntity> results = getEditableSpacesFilterQuery(userId, null).objects(offset, limit);
1678 
1679     while (results.hasNext()) {
1680       SpaceEntity currentSpace = results.next();
1681       Space space = new Space();
1682       fillSpaceFromEntity(currentSpace, space);
1683       spaces.add(space);
1684     }
1685 
1686     return spaces;
1687   }
1688 
1689   /**
1690    * {@inheritDoc}
1691    */
1692   public List<Space> getEditableSpacesByFilter(String userId, SpaceFilter spaceFilter, long offset, long limit) {
1693 
1694     List<Space> spaces = new ArrayList<Space>();
1695 
1696     //
1697     QueryResult<SpaceEntity> results = getEditableSpacesFilterQuery(userId, spaceFilter).objects(offset, limit);
1698 
1699     while (results.hasNext()) {
1700       SpaceEntity currentSpace = results.next();
1701       Space space = new Space();
1702       fillSpaceFromEntity(currentSpace, space);
1703       spaces.add(space);
1704     }
1705 
1706     return spaces;
1707   }
1708 
1709   /*
1710     All spaces
1711    */
1712 
1713   /**
1714    * {@inheritDoc}
1715    */
1716   public int getAllSpacesCount() throws SpaceStorageException {
1717 
1718     // TODO : use property to improve the perfs
1719 
1720     return getSpaceRoot().getSpaces().size();
1721 
1722   }
1723 
1724   /**
1725    * {@inheritDoc}
1726    */
1727   public List<Space> getAllSpaces() throws SpaceStorageException {
1728 
1729     List<Space> spaces = new ArrayList<Space>();
1730 
1731     QueryResult<SpaceEntity> results = getSpacesByFilterQuery(null).objects();
1732 
1733     while (results.hasNext()) {
1734       SpaceEntity currentSpace = results.next();
1735       Space space = new Space();
1736       fillSpaceFromEntity(currentSpace, space);
1737       spaces.add(space);
1738     }
1739     return spaces;
1740   }
1741 
1742   /**
1743    * {@inheritDoc}
1744    */
1745   public int getAllSpacesByFilterCount(SpaceFilter spaceFilter) {
1746 
1747     if (validateFilter(spaceFilter)) {
1748       return getSpacesByFilterQuery(spaceFilter).objects().size();
1749     }
1750     else {
1751       return 0;
1752     }
1753 
1754   }
1755 
1756 
1757   /*
1758     Get spaces
1759    */
1760 
1761   /**
1762    * {@inheritDoc}
1763    */
1764   public List<Space> getSpaces(long offset, long limit) throws SpaceStorageException {
1765     List<Space> spaces = new ArrayList<Space>();
1766 
1767     QueryResult<SpaceEntity> results = getSpacesByFilterQuery(null).objects(offset, limit);
1768 
1769     while (results.hasNext()) {
1770       SpaceEntity currentSpace = results.next();
1771       Space space = new Space();
1772       fillSpaceFromEntity(currentSpace, space);
1773       spaces.add(space);
1774     }
1775     return spaces;
1776   }
1777 
1778   /**
1779    * {@inheritDoc}
1780    */
1781   public List<Space> getSpacesByFilter(SpaceFilter spaceFilter, long offset, long limit) {
1782 
1783     List<Space> spaces = new ArrayList<Space>();
1784 
1785     QueryResult<SpaceEntity> results = getSpacesByFilterQuery(spaceFilter).objects(offset, limit);
1786 
1787     while (results.hasNext()) {
1788       SpaceEntity currentSpace = results.next();
1789       Space space = new Space();
1790       fillSpaceFromEntity(currentSpace, space);
1791       spaces.add(space);
1792     }
1793     return spaces;
1794   }
1795 
1796   /**
1797    * {@inheritDoc}
1798    */
1799   public Space getSpaceById(String id) throws SpaceStorageException {
1800 
1801     try {
1802 
1803       SpaceEntity spaceEntity = _findById(SpaceEntity.class, id);
1804 
1805       Space space = new Space();
1806 
1807       fillSpaceFromEntity(spaceEntity, space);
1808 
1809       return space;
1810 
1811     }
1812     catch (NodeNotFoundException e) {
1813       return null;
1814     }
1815 
1816   }
1817   
1818   /**
1819    * {@inheritDoc}
1820    */
1821   public Space getSpaceSimpleById(String id) throws SpaceStorageException {
1822 
1823     try {
1824 
1825       SpaceEntity spaceEntity = _findById(SpaceEntity.class, id);
1826 
1827       Space space = new Space();
1828 
1829       fillSpaceSimpleFromEntity(spaceEntity, space);
1830 
1831       return space;
1832 
1833     }
1834     catch (NodeNotFoundException e) {
1835       return null;
1836     }
1837 
1838   }
1839 
1840   /**
1841    * {@inheritDoc}
1842    */
1843   public Space getSpaceByPrettyName(String spacePrettyName) throws SpaceStorageException {
1844 
1845     try {
1846 
1847       SpaceEntity entity = _findByPath(SpaceEntity.class, String.format("/production/soc:spaces/soc:%s", spacePrettyName));
1848 
1849       Space space = new Space();
1850       fillSpaceFromEntity(entity, space);
1851 
1852       return space;
1853 
1854     }
1855     catch (NodeNotFoundException e) {
1856       return null;
1857     }
1858   }
1859 
1860   /**
1861    * {@inheritDoc}
1862    */
1863   public Space getSpaceByGroupId(String groupId) throws SpaceStorageException {
1864 
1865     // TODO : avoid JCR query ?
1866 
1867     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
1868     WhereExpression whereExpression = new WhereExpression();
1869 
1870     builder.where(whereExpression.equals(SpaceEntity.groupId, groupId).toString());
1871 
1872     QueryResult<SpaceEntity> result = builder.get().objects();
1873 
1874     if (result.hasNext()) {
1875       SpaceEntity entity =  result.next();
1876       Space space = new Space();
1877 
1878       fillSpaceFromEntity(entity, space);
1879 
1880       return space;
1881     }
1882     else {
1883       return null;
1884     }
1885 
1886   }
1887 
1888   /**
1889    * {@inheritDoc}
1890    */
1891   public Space getSpaceByUrl(String url) throws SpaceStorageException {
1892 
1893     // TODO : avoid JCR query ?
1894 
1895     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
1896 
1897     if (url != null) {
1898       WhereExpression whereExpression = new WhereExpression();
1899       whereExpression.equals(SpaceEntity.url, url);
1900       builder.where(whereExpression.toString());
1901     }
1902 
1903     QueryResult<SpaceEntity> result = builder.get().objects();
1904 
1905     if (result.hasNext()) {
1906 
1907       Space space = new Space();
1908       SpaceEntity entity =  builder.get().objects().next();
1909 
1910       fillSpaceFromEntity(entity, space);
1911 
1912       return space;
1913 
1914     }
1915     else {
1916       return null;
1917     }
1918 
1919   }
1920 
1921   @Override
1922   public void updateSpaceAccessed(String remoteId, Space space) throws SpaceStorageException {
1923     try {
1924       IdentityEntity identityEntity = identityStorage._findIdentityEntity(OrganizationIdentityProvider.NAME, remoteId);
1925       SpaceListEntity listRef = RefType.MEMBER.refsOf(identityEntity);
1926       
1927       SpaceEntity spaceEntity = _findById(SpaceEntity.class, space.getId());
1928 
1929       SpaceRef ref = listRef.getRef(spaceEntity.getName());
1930       if (!ref.getName().equals(spaceEntity.getName())) {
1931         ref.setName(spaceEntity.getName());
1932       }
1933       ref.setSpaceRef(spaceEntity);
1934 
1935 //      getSession().save();
1936 
1937     } catch (NodeNotFoundException e) {
1938       LOG.warn(e.getMessage(), e);
1939     }
1940   }
1941 
1942   @Override
1943   public List<Space> getLastAccessedSpace(SpaceFilter filter, int offset, int limit) throws SpaceStorageException {
1944     try {
1945       IdentityEntity identityEntity = identityStorage._findIdentityEntity(OrganizationIdentityProvider.NAME, filter.getRemoteId());
1946       SpaceListEntity listRef = RefType.MEMBER.refsOf(identityEntity);
1947       Map<String, SpaceRef> mapRefs = listRef.getRefs();
1948       
1949       //
1950       ChromatticSessionImpl chromatticSession = (ChromatticSessionImpl) getSession();
1951       Map<SpaceRef, Long> spaceRefs = new LinkedHashMap<SpaceRef, Long>();
1952       Space space = null;
1953       
1954       //
1955       for(Map.Entry<String, SpaceRef> entry :  mapRefs.entrySet()) {
1956         SpaceRef ref = entry.getValue();
1957         Node node = chromatticSession.getNode(ref);
1958         Property p = getProperty(node, JCRProperties.JCR_LAST_MODIFIED_DATE.getName());
1959         long lastModifedDate = p == null ? 0 : p.getDate().getTimeInMillis();
1960 
1961         // Lazy clean up
1962         if (ref.getSpaceRef() == null) {
1963           listRef.removeRef(entry.getKey());
1964           continue;
1965         }
1966 
1967         if (filter.getAppId() == null) {
1968           spaceRefs.put(ref, lastModifedDate);
1969         } else {
1970           if (ref.getSpaceRef().getApp().toLowerCase().indexOf(filter.getAppId().toLowerCase()) > 0) {
1971             spaceRefs.put(ref, lastModifedDate);
1972           }
1973         }
1974       }
1975       spaceRefs = StorageUtils.sortMapByValue(spaceRefs, false);
1976       
1977       List<Space> got = new LinkedList<Space>();
1978       Iterator<SpaceRef> it1 = spaceRefs.keySet().iterator();
1979       _skip(it1, offset);
1980 
1981       //
1982       int numberOfSpace = 0;
1983       while (it1.hasNext()) {
1984         space = new Space();
1985         fillSpaceSimpleFromEntity(it1.next().getSpaceRef(), space);
1986         got.add(space);
1987         //
1988         if (++numberOfSpace == limit) {
1989           break;
1990         }
1991       }
1992 
1993       return got;
1994     } catch (NodeNotFoundException e) {
1995       LOG.warn("Get last accessed spaces failure.", e);
1996     } catch (RepositoryException e) {
1997       LOG.warn("Get last accessed spaces failure.", e);
1998     }
1999     
2000     //
2001     return Collections.emptyList();
2002   }
2003 
2004   public List<Space> getLastSpaces(final int limit) {
2005     QueryBuilder<SpaceEntity> builder = getSession().createQueryBuilder(SpaceEntity.class);
2006 
2007     Ordering ordering = Ordering.valueOf(Sorting.OrderBy.DESC.toString());
2008 
2009     builder.orderBy(SpaceEntity.createdTime.getName(), ordering);
2010 
2011     QueryResult<SpaceEntity> result = builder.get().objects(0L, (long)limit);
2012 
2013     List<Space> got = new LinkedList<Space>();
2014     while (result.hasNext()) {
2015       SpaceEntity entity =  result.next();
2016       Space space = new Space();
2017 
2018       fillSpaceFromEntity(entity, space);
2019 
2020       got.add(space);
2021     }
2022     return got;
2023   }
2024 
2025   public int getNumberOfMemberPublicSpaces(String userId) {
2026     return getSpacesOfMemberQuery(userId).objects().size();
2027   }
2028   
2029   @Override
2030   public List<Space> getVisitedSpaces(SpaceFilter filter, int offset, int limit) throws SpaceStorageException {
2031 
2032     try {
2033       IdentityEntity identityEntity = identityStorage._findIdentityEntity(OrganizationIdentityProvider.NAME, filter.getRemoteId());
2034       SpaceListEntity listRef = RefType.MEMBER.refsOf(identityEntity);
2035       Map<String, SpaceRef> mapRefs = listRef.getRefs();
2036       
2037       //
2038       Map<SpaceRef, Long> visitedSpaceRefs = new LinkedHashMap<SpaceRef, Long>();
2039       List<SpaceRef> neverVisitedSpaceRefs = new LinkedList<SpaceRef>();
2040       
2041       visitedSpaceRefs = getSpaceRefs(mapRefs, visitedSpaceRefs, neverVisitedSpaceRefs, filter.getAppId());
2042       Iterator<SpaceRef> spaceRefs = visitedSpaceRefs.keySet().iterator();
2043       
2044       if (offset < visitedSpaceRefs.size()) {
2045         _skip(spaceRefs, offset);
2046         offset = 0;
2047       } else {
2048         _skip(spaceRefs, offset);
2049         offset = offset - (visitedSpaceRefs.size());
2050       }
2051       
2052       //
2053       List<Space> got = new LinkedList<Space>();
2054       //priority for visited spaces to return
2055       getSpacesFromSpaceRefs(spaceRefs, got, limit);
2056       
2057       // process the spaces which are never be visited
2058       int remain = limit - got.size();
2059       if (neverVisitedSpaceRefs.isEmpty() || (remain == 0)) {
2060         return got;
2061       }
2062 
2063       spaceRefs = neverVisitedSpaceRefs.iterator();
2064       _skip(spaceRefs, offset);
2065       //
2066       List<Space> neverVisitedSpaces = new LinkedList<Space>();
2067       getSpacesFromSpaceRefs(spaceRefs, neverVisitedSpaces, -1);
2068       neverVisitedSpaces = StorageUtils.sortSpaceByName(neverVisitedSpaces, true);
2069 
2070       //
2071       got.addAll(neverVisitedSpaces.subList(0, Math.min(remain, neverVisitedSpaces.size())));
2072       
2073       return got;
2074     } catch (NodeNotFoundException e) {
2075       LOG.warn(e.getMessage(), e);
2076     } catch (RepositoryException e) {
2077       LOG.warn(e.getMessage(), e);
2078     }
2079     //
2080     return Collections.emptyList();
2081   }
2082   
2083   private Map<SpaceRef, Long> getSpaceRefs(Map<String, SpaceRef> spaceRefs, Map<SpaceRef, Long> visitedSpaceRefs, List<SpaceRef> neverVisitedSpaceRefs, String appId) throws RepositoryException {
2084     //
2085     ChromatticSessionImpl chromatticSession = (ChromatticSessionImpl) getSession();
2086     
2087     for (Entry<String, SpaceRef> entry : spaceRefs.entrySet()) {
2088       SpaceRef ref = entry.getValue();
2089       Node node = chromatticSession.getNode(ref);
2090       Property p1 = getProperty(node, JCRProperties.JCR_LAST_CREATED_DATE.getName());
2091       Property p2 = getProperty(node, JCRProperties.JCR_LAST_MODIFIED_DATE.getName());
2092       long createdTime = p1 == null ? 0 : p1.getDate().getTimeInMillis();
2093       long lastModifedDate = p2 == null ? 0 : p2.getDate().getTimeInMillis();
2094       
2095       boolean isValid = false;
2096       if (appId == null) {
2097         isValid = true;
2098       } else {
2099         if (ref.getSpaceRef().getApp().toLowerCase().indexOf(appId.toLowerCase()) > 0) {
2100           isValid = true;
2101         }
2102 
2103       }
2104       
2105       //The never visited spaces which have last modified date different with the created time less than 2 seconds
2106       if (lastModifedDate - createdTime < TWO_SECONDS && isValid) {
2107         neverVisitedSpaceRefs.add(ref);
2108       } else if (isValid) {
2109         visitedSpaceRefs.put(ref, lastModifedDate);
2110       }
2111     }
2112     
2113     //sort visited space by modified date
2114     return StorageUtils.sortMapByValue(visitedSpaceRefs, false);
2115   }
2116   
2117   private void getSpacesFromSpaceRefs(Iterator<SpaceRef> it, List<Space> list, int limit) {
2118     Space space = null;
2119     //
2120     int numberOfSpace = 0;
2121     while (it.hasNext()) {
2122       space = new Space();
2123       fillSpaceFromEntity(it.next().getSpaceRef(), space);
2124       list.add(space);
2125       //
2126       if (++numberOfSpace == limit) {
2127         break;
2128       }
2129     }
2130   }
2131 
2132   private Property getProperty(Node node, String propertyName) {
2133     try {
2134       return node.getProperty(propertyName);
2135     } catch (RepositoryException e) {
2136       LOG.error(String.format("Get property %s failed", propertyName));
2137     }
2138     return null;
2139   }
2140 
2141   @Override
2142   public List<String> getMemberSpaceIds(String identityId, int offset, int limit) throws SpaceStorageException {
2143     List<String> identitiesId = new ArrayList<String>();
2144     try {
2145       IdentityEntity identityEntity = _findById(IdentityEntity.class, identityId);
2146       Set<String> spaceNames = identityEntity.getSpaces().getRefs().keySet();
2147       ProviderEntity providerEntity = getProviderRoot().getProvider(SpaceIdentityProvider.NAME);
2148       for (String spacePrettyName : spaceNames) {
2149         IdentityEntity spaceIdentity = providerEntity.getIdentities().get(spacePrettyName);
2150         if (spaceIdentity != null) {
2151           identitiesId.add(spaceIdentity.getId());
2152         }
2153       }
2154     } catch (Exception e) {
2155       LOG.error("Failed to get list of space identity of current user");
2156     }
2157     return identitiesId;
2158   }
2159 }