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.manager;
18  
19  import org.exoplatform.commons.utils.ListAccess;
20  import org.exoplatform.container.PortalContainer;
21  import org.exoplatform.social.core.identity.ConnectionFilterListAccess;
22  import org.exoplatform.social.core.identity.ConnectionListAccess;
23  import org.exoplatform.social.core.identity.model.Identity;
24  import org.exoplatform.social.core.profile.ProfileFilter;
25  import org.exoplatform.social.core.relationship.RelationshipLifeCycle;
26  import org.exoplatform.social.core.relationship.RelationshipListener;
27  import org.exoplatform.social.core.relationship.RelationshipListenerPlugin;
28  import org.exoplatform.social.core.relationship.model.Relationship;
29  import org.exoplatform.social.core.relationship.model.Relationship.Type;
30  import org.exoplatform.social.core.storage.api.IdentityStorage;
31  import org.exoplatform.social.core.storage.api.RelationshipStorage;
32  import org.exoplatform.social.core.storage.RelationshipStorageException;
33  
34  import java.util.*;
35  
36  /**
37   * The Class RelationshipManager implements RelationshipManager without caching.
38   * 
39   * @since Nov 24, 2010
40   * @version 1.2.0-GA
41   */
42  public class RelationshipManagerImpl implements RelationshipManager {
43    /** The activityStorage. */
44    protected RelationshipStorage   storage;
45  
46    protected IdentityStorage identityStorage;
47  
48    /**
49     * lifecycle of a relationship.
50     */
51    protected RelationshipLifeCycle lifeCycle = new RelationshipLifeCycle();
52  
53    private IdentityManager identityManager;
54    
55    /**
56     * The default offset when get list identities with connection list access.
57     * 
58     * @since 1.2.0-Beta3
59     */
60    protected static final int OFFSET = 0;
61    
62    /**
63     * The default limit when get list identities with connection list access.
64     * 
65     * @since 1.2.0-Beta3
66     */
67    protected static final int LIMIT = 200;
68  
69    /**
70     * Instantiates a new relationship manager.
71     * 
72     * @param relationshipStorage
73     */
74    public RelationshipManagerImpl(IdentityStorage identityStorage, RelationshipStorage relationshipStorage) {
75      this.storage = relationshipStorage;
76      this.identityStorage = identityStorage;
77    }
78  
79    /**
80     * {@inheritDoc}
81     */
82    public Relationship get(String relationshipId) {
83      Relationship relationship = null;
84      try {
85        relationship = storage.getRelationship(relationshipId);
86      } catch (Exception e) {
87        return null;
88      }
89      return relationship;
90    }
91  
92    /**
93     * {@inheritDoc}
94     */
95    public Relationship invite(Identity sender, Identity receiver) throws RelationshipStorageException {
96      return this.inviteToConnect(sender, receiver);
97    }
98  
99    /**
100    * {@inheritDoc}
101    */
102   public void save(Relationship relationship) throws RelationshipStorageException {
103     this.update(relationship);
104   }
105 
106   /**
107    * {@inheritDoc}
108    */
109   public void confirm(Relationship relationship) throws RelationshipStorageException {
110     this.confirm(relationship.getReceiver(), relationship.getSender());
111   }
112 
113   /**
114    * {@inheritDoc}
115    */
116   public void deny(Relationship relationship) throws RelationshipStorageException {
117     this.deny(relationship.getReceiver(), relationship.getSender());
118   }
119 
120   /**
121    * {@inheritDoc}
122    */
123   public void remove(Relationship relationship) throws RelationshipStorageException {
124     this.delete(relationship);
125   }
126 
127   /**
128    * {@inheritDoc}
129    */
130   public void ignore(Relationship relationship) throws RelationshipStorageException {
131     this.ignore(relationship.getSender(), relationship.getReceiver());
132   }
133 
134   /**
135    * {@inheritDoc}
136    */
137   public List<Relationship> getPending(Identity sender) throws RelationshipStorageException {
138     return getSender(sender, Relationship.Type.PENDING, null);
139   }
140 
141   /**
142    * {@inheritDoc}
143    */
144   public List<Relationship> getPending(Identity sender, List<Identity> identities) throws RelationshipStorageException {
145     return getSender(sender, Relationship.Type.PENDING, identities);
146   }
147 
148   /**
149    * {@inheritDoc}
150    */
151   public List<Relationship> getIncoming(Identity receiver) throws RelationshipStorageException {
152     return getReceiver(receiver, Relationship.Type.PENDING, null);
153   }
154 
155   /**
156    * {@inheritDoc}
157    */
158   public List<Relationship> getIncoming(Identity receiver, List<Identity> identities) throws RelationshipStorageException {
159     return getReceiver(receiver, Relationship.Type.PENDING, identities);
160   }
161 
162   /**
163    * {@inheritDoc}
164    */
165   public List<Relationship> getConfirmed(Identity identity) throws RelationshipStorageException {
166     return getRelationships(identity, Relationship.Type.CONFIRMED, null);
167   }
168 
169   /**
170    * {@inheritDoc}
171    */
172   public List<Relationship> getConfirmed(Identity identity, List<Identity> identities) throws RelationshipStorageException {
173     return getRelationships(identity, Relationship.Type.CONFIRMED, identities);
174   }
175 
176   /**
177    * {@inheritDoc}
178    */
179   public List<Relationship> getAll(Identity identity) throws RelationshipStorageException {
180     return getRelationships(identity, null, null);
181   }
182 
183   /**
184    * {@inheritDoc}
185    */
186   public List<Relationship> getAll(Identity identity, List<Identity> identities) throws RelationshipStorageException {
187     return getRelationships(identity, null, identities);
188   }
189 
190   /**
191    * {@inheritDoc}
192    */
193   public List<Relationship> getAll(Identity identity, Relationship.Type type,
194                                                 List<Identity> identities) throws RelationshipStorageException {
195     return getRelationships(identity, type, identities);
196   }
197 
198   /**
199    * {@inheritDoc}
200    */
201   public Relationship get(Identity identity1, Identity identity2) throws RelationshipStorageException {
202     return storage.getRelationship(identity1, identity2);
203   }
204 
205   /**
206    * {@inheritDoc}
207    */
208   public Relationship.Type getStatus(Identity identity1, Identity identity2) throws RelationshipStorageException {
209     Relationship relationship = get(identity1, identity2);
210     return relationship == null ? null : relationship.getStatus();
211   }
212 
213   /**
214    * Registers a RelationshipLister.
215    *
216    * @param listener
217    */
218   public void registerListener(RelationshipListener listener) {
219     lifeCycle.addListener(listener);
220   }
221 
222   /**
223    * Unregisters a RelationshipLister.
224    *
225    * @param listener
226    */
227   public void unregisterListener(RelationshipListener listener) {
228     lifeCycle.removeListener(listener);
229   }
230 
231   /**
232    * Adds a RelationshipListenerPlugin.
233    *
234    * @param plugin
235    */
236   public void addListenerPlugin(RelationshipListenerPlugin plugin) {
237     registerListener(plugin);
238   }
239 
240   /**
241    * Gets the relationship activityStorage.
242    *
243    * @return storage
244    */
245   protected RelationshipStorage getStorage() {
246     return storage;
247   }
248 
249   /**
250    * Sets the relationship activityStorage.
251    *
252    * @param storage
253    */
254   protected void setStorage(RelationshipStorage storage) {
255     this.storage = storage;
256   }
257 
258   /**
259    * Gets the relationship life cycle.
260    *
261    * @return lifeCycle
262    */
263   protected RelationshipLifeCycle getLifeCycle() {
264     return lifeCycle;
265   }
266 
267   /**
268    * Sets thre relationship life cycle.
269    *
270    * @param lifeCycle
271    */
272   protected void setLifeCycle(RelationshipLifeCycle lifeCycle) {
273     this.lifeCycle = lifeCycle;
274   }
275 
276   /**
277    * Get relationships by identity and status from cache or activityStorage
278    * 
279    * @param identity
280    * @param identities
281    * @return list of relationship
282    * @throws RelationshipStorageException
283    */
284   protected List<Relationship> getRelationships(Identity identity, Relationship.Type type,
285                                                 List<Identity> identities) throws RelationshipStorageException {
286     return storage.getRelationships(identity, type, identities);
287   }
288 
289   /**
290    * Get relationships by identity and status and identities from activityStorage
291    * 
292    * @param sender
293    * @return list of relationship
294    * @throws RelationshipStorageException
295    */
296   protected List<Relationship> getSender(Identity sender, Relationship.Type type,
297                                          List<Identity> identities) throws RelationshipStorageException {
298     return storage.getSenderRelationships(sender, type, identities);
299   }
300 
301   /**
302    * Get relationships by identity and status from cache or activityStorage
303    * 
304    * @param receiver
305    * @param identities
306    * @return list of relationship
307    * @throws RelationshipStorageException
308    */
309   protected List<Relationship> getReceiver(Identity receiver, Relationship.Type type,
310                                            List<Identity> identities) throws RelationshipStorageException {
311     return storage.getReceiverRelationships(receiver, type, identities);
312   }
313 
314   /**
315    * {@inheritDoc}
316    */
317   public Relationship create(Identity sender, Identity receiver) {
318     return new Relationship(sender, receiver);
319   }
320 
321   /**
322    * {@inheritDoc}
323    */
324   public List<Identity> findRelationships(Identity ownerIdentity, Type relationshipType) throws RelationshipStorageException {
325     List<Relationship> allRelationships = getAll(ownerIdentity, relationshipType, null);
326     List<Identity> identities = new ArrayList<Identity>();
327     if (allRelationships == null || allRelationships.size() == 0) {
328       return identities;
329     }
330     for(Relationship relationship : allRelationships) {
331       identities.add(relationship.getPartner(ownerIdentity));
332     }
333     return identities;
334   }
335 
336   /**
337    * {@inheritDoc}
338    */
339   public List<Relationship> findRoute(Identity sender, Identity receiver) throws RelationshipStorageException {
340     List<Relationship> route = new ArrayList<Relationship>();
341     route.add(get(sender,receiver));
342     return route;
343   }
344 
345   /**
346    * {@inheritDoc}
347    */
348   public Type getConnectionStatus(Identity fromIdentity, Identity toIdentity) throws Exception {
349     return getStatus(fromIdentity, toIdentity);
350   }
351   
352   /**
353    * {@inheritDoc}
354    */
355   public ListAccess<Identity> getConnections(Identity identity) {
356     return (new ConnectionListAccess(storage, identity, ConnectionListAccess.Type.CONNECTION));
357   }
358   
359   /**
360    * {@inheritDoc}
361    */
362   public List<Relationship> getContacts(Identity currIdentity, List<Identity> identities) throws RelationshipStorageException {
363     return getAll(currIdentity, Type.CONFIRMED, identities);
364   }
365 
366   /**
367    * {@inheritDoc}
368    */
369   public List<Relationship> getContacts(Identity identity) throws RelationshipStorageException {
370     return getAll(identity, Type.CONFIRMED, null);
371   }
372 
373   /**
374    * {@inheritDoc}
375    */
376   public List<Identity> getIdentities(Identity id) throws Exception {
377     return Arrays.asList(this.getConnections(id).load(OFFSET, LIMIT));
378   }
379 
380   /**
381    * {@inheritDoc}
382    */
383   public List<Relationship> getPendingRelationships(Identity identity) throws RelationshipStorageException {
384     return getPending(identity);
385   }
386 
387   /**
388    * {@inheritDoc}
389    */
390   public List<Relationship> getPendingRelationships(Identity identity, boolean toConfirm) throws RelationshipStorageException {
391     return getAll(identity, Type.PENDING, null);
392   }
393 
394   /**
395    * {@inheritDoc}
396    */
397   public List<Relationship> getPendingRelationships(Identity currIdentity, List<Identity> identities,
398                                                     boolean toConfirm) throws RelationshipStorageException {
399     return getAll(currIdentity, Type.PENDING, identities);
400   }
401 
402   /**
403    * {@inheritDoc}
404    */
405   public Relationship getRelationship(Identity sender, Identity receiver) throws RelationshipStorageException {
406     return get(sender, receiver);
407   }
408 
409   /**
410    * {@inheritDoc}
411    */
412   public Relationship getRelationshipById(String id) throws RelationshipStorageException {
413     return get(id);
414   }
415 
416   /**
417    * {@inheritDoc}
418    */
419   public Type getRelationshipStatus(Relationship rel, Identity id) {
420     return rel.getStatus();
421   }
422 
423   /**
424    * {@inheritDoc}
425    */
426   public List<Relationship> getRelationshipsByIdentityId(String id) throws RelationshipStorageException {
427     return getAll(getIdentityManager().getIdentity(id));
428   }
429 
430   private IdentityManager getIdentityManager() {
431     if (identityManager == null) {
432       identityManager = (IdentityManager) PortalContainer.getInstance().getComponentInstanceOfType(IdentityManager.class);
433     }
434     return identityManager;
435   }
436 
437   /**
438    * {@inheritDoc}
439    */
440   public void saveRelationship(Relationship relationship) throws RelationshipStorageException {
441     save(relationship);
442   }
443 
444   /**
445    * {@inheritDoc}
446    */
447   public List<Relationship> getAllRelationships(Identity identity) throws RelationshipStorageException {
448     return getAll(identity);
449   }
450 
451   /**
452    * {@inheritDoc}
453    */
454   public void confirm(Identity invitedIdentity, Identity invitingIdentity) {
455     Relationship relationship = get(invitedIdentity, invitingIdentity);
456     if (relationship != null && relationship.getStatus() == Relationship.Type.PENDING) {
457       relationship.setStatus(Relationship.Type.CONFIRMED);
458       this.update(relationship);
459       lifeCycle.relationshipConfirmed(this, relationship);
460     }
461   }
462 
463   /**
464    * {@inheritDoc}
465    */
466   public void delete(Relationship existingRelationship) {
467     storage.removeRelationship(existingRelationship);
468     lifeCycle.relationshipRemoved(this, existingRelationship);
469   }
470 
471   /**
472    * {@inheritDoc}
473    */
474   public void deny(Identity invitedIdentity, Identity invitingIdentity) {
475     Relationship relationship = this.get(invitedIdentity, invitingIdentity);
476     if (relationship != null) {
477       //    relationship.setStatus(Relationship.Type.IGNORED);
478       //  save(relationship);
479       // TODO: now just remove, implement later
480       storage.removeRelationship(relationship);
481       lifeCycle.relationshipDenied(this, relationship);
482     }
483   }
484 
485   /**
486    * {@inheritDoc}
487    */
488   public ListAccess<Identity> getAllWithListAccess(Identity existingIdentity) {
489     return new ConnectionListAccess(this.storage, existingIdentity, ConnectionListAccess.Type.ALL);
490   }
491 
492   /**
493    * {@inheritDoc}
494    */
495   public ListAccess<Identity> getIncomingWithListAccess(Identity existingIdentity) {
496     return new ConnectionListAccess(this.storage, existingIdentity, ConnectionListAccess.Type.INCOMING);
497   }
498 
499   /**
500    * {@inheritDoc}
501    */
502   public ListAccess<Identity> getOutgoing(Identity existingIdentity) {
503     return new ConnectionListAccess(this.storage, existingIdentity, ConnectionListAccess.Type.OUTGOING);
504   }
505 
506   /**
507    * {@inheritDoc}
508    */
509   public void ignore(Identity sender, Identity receiver) {
510     Relationship relationship = this.get(sender, receiver);
511     if (relationship == null || !Type.IGNORED.equals(relationship.getStatus())) {
512       relationship = new Relationship(sender, receiver);
513       relationship.setStatus(Type.IGNORED);
514       save(relationship);
515       lifeCycle.relationshipIgnored(this, relationship);
516     }
517   }
518 
519   /**
520    * {@inheritDoc}
521    */
522   public Relationship inviteToConnect(Identity invitingIdentity, Identity invitedIdentity) {
523     Relationship relationship = get(invitingIdentity, invitedIdentity);
524     if (relationship == null || Type.IGNORED.equals(relationship.getStatus())) {
525       relationship = new Relationship(invitingIdentity, invitedIdentity);
526       relationship.setStatus(Type.PENDING);
527       this.update(relationship);
528       lifeCycle.relationshipRequested(this, relationship);
529     }
530     return relationship;
531   }
532 
533   /**
534    * {@inheritDoc}
535    */
536   public void update(Relationship existingRelationship) {
537     String senderId = existingRelationship.getSender().getId();
538     String receiverId = existingRelationship.getReceiver().getId();
539     if (senderId.equals(receiverId)) {
540       throw new RelationshipStorageException(RelationshipStorageException.Type.FAILED_TO_SAVE_RELATIONSHIP,
541                                              "the two identity are the same");
542     }
543     storage.saveRelationship(existingRelationship);
544   }
545 
546   public ListAccess<Identity> getConnectionsByFilter(Identity existingIdentity, ProfileFilter profileFilter) {
547     return new ConnectionFilterListAccess(identityStorage, this.storage, existingIdentity, profileFilter,
548                                           ConnectionFilterListAccess.Type.PROFILE_FILTER_CONNECTION);
549   }
550 
551   public ListAccess<Identity> getIncomingByFilter(Identity existingIdentity, ProfileFilter profileFilter) {
552     return new ConnectionFilterListAccess(identityStorage, this.storage, existingIdentity, profileFilter,
553                                           ConnectionFilterListAccess.Type.PROFILE_FILTER_INCOMMING);
554   }
555 
556   public ListAccess<Identity> getOutgoingByFilter(Identity existingIdentity, ProfileFilter profileFilter) {
557     
558     return new ConnectionFilterListAccess(identityStorage, this.storage, existingIdentity, profileFilter,
559                                           ConnectionFilterListAccess.Type.PROFILE_FILTER_OUTGOING);
560   }
561 
562   public Map<Identity, Integer> getSuggestions(Identity identity, int maxConnections, 
563                                                 int maxConnectionsToLoad, int maxSuggestions) {
564     return storage.getSuggestions(identity, maxConnections, maxConnectionsToLoad, 
565                                                                 maxSuggestions);
566   }
567 
568   public Map<Identity, Integer> getSuggestions(Identity identity, int offset, int limit) {
569     Map<Identity, Integer> result = storage.getSuggestions(identity, -1, -1, offset + limit);
570     if (result != null && !result.isEmpty()) {
571       if (offset > 0) {
572         result = new LinkedHashMap<Identity, Integer>(result);
573         int o = 0;
574         for (Iterator<Map.Entry<Identity, Integer>> it = result.entrySet().iterator(); it.hasNext() && o < offset; o++) {
575           it.next();
576           it.remove();
577         }
578       }
579       if (result.size() > limit) {
580         result = new LinkedHashMap<Identity, Integer>(result);
581         int i = 0;
582         for (Iterator<Map.Entry<Identity, Integer>> it = result.entrySet().iterator(); it.hasNext(); i++) {
583           it.next();
584           if (i >= limit)
585             it.remove();
586         }
587       }
588     }
589     return result;
590   }
591 
592   @Override
593   public List<Identity> getLastConnections(Identity identity, int limit) {
594     return storage.getLastConnections(identity, limit);
595   }
596   
597   /**
598    * {@inheritDoc}
599    */
600   public List<Relationship> getRelationshipsByStatus(Identity identity, Relationship.Type type, int offset, int limit) {
601     return storage.getRelationshipsByStatus(identity, type, offset, limit);
602   }
603   
604   /**
605    * {@inheritDoc}
606    */
607   public int getRelationshipsCountByStatus(Identity identity, Relationship.Type type) {
608     return storage.getRelationshipsCountByStatus(identity, type);
609   }
610 }