View Javadoc

1   package net.sf.josceleton.connection.impl.service.user;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.Collections;
6   import java.util.HashMap;
7   import java.util.Map;
8   
9   import net.sf.josceleton.commons.collection.SafeLinkedHashSet;
10  import net.sf.josceleton.core.api.entity.User;
11  
12  /**
13   * @since 0.3
14   */
15  class UserServiceCollectionImpl implements UserServiceCollection {
16  
17  	private final Map<Integer, User> usersById = new HashMap<Integer, User>();
18  	
19  	private final Collection<User> waitingUsers = new SafeLinkedHashSet<User>();
20  	
21  	private final Collection<User> processingUsers = new SafeLinkedHashSet<User>();
22  
23  	
24  	@Override public final void add(final User newUser) {
25  		this.usersById.put(Integer.valueOf(newUser.getOsceletonId()), newUser);
26  		this.waitingUsers.add(newUser);
27  	}
28  
29  	@Override public final void moveToProcessing(final User processingUser) {
30  		this.waitingUsers.remove(processingUser);
31  		this.processingUsers.add(processingUser);
32  	}
33  
34  	@Override public final User get(final Integer osceletonId) {
35  		return this.usersById.get(osceletonId);
36  	}
37  
38  	@Override public final Collection<User> getProcessing() {
39  		return Collections.unmodifiableCollection(this.processingUsers);
40  	}
41  
42  	@Override public final Collection<User> getWaiting() {
43  		return Collections.unmodifiableCollection(this.waitingUsers);
44  	}
45  
46  	@Override public final void checkIfYetRegistered(
47  			final Integer osceletonUserId,
48  			final UserServiceCollectionResponder responder) {
49  		if(this.usersById.containsKey(osceletonUserId) == false) {
50  			return;
51  		}
52  		
53  		this.clearUsers(this.processingUsers, responder);
54  		this.clearUsers(this.waitingUsers, responder);
55  // MINOR assert this.usersById.isEmpty() : "usersById should be empty after fallback!";
56  	}
57  
58  	
59  	@Override public final User remove(final Integer osceletonUserId, final UserServiceCollectionResponder responder) {
60  		final User removedStoredUser = this.usersById.remove(osceletonUserId);
61  		final boolean wasPreviouslyStored = removedStoredUser != null;
62  		
63  		final User userToDispatch;
64  		if(wasPreviouslyStored == true) {
65  			// simple case: user was already known to josceleton (was either waiting or processing)
66  			userToDispatch = removedStoredUser;
67  		} else {
68  			// this is an EXPECTED state; kinect detected user before josceleton started listening, but lost again.
69  			// artificially invoke one state step before
70  			userToDispatch = responder.lookupProcessingUser(osceletonUserId);
71  		}
72  		
73  		if(wasPreviouslyStored == true && this.waitingUsers.contains(removedStoredUser) == true) {
74  			this.waitingUsers.remove(removedStoredUser);
75  		} else {
76  			final User processingUserToRemove;
77  			if(wasPreviouslyStored == false) {
78  				processingUserToRemove = userToDispatch;
79  			} else {
80  				processingUserToRemove = removedStoredUser;
81  			}
82  			this.processingUsers.remove(processingUserToRemove);
83  		}
84  		
85  		return userToDispatch;
86  	}
87  
88  	@Override
89  	public User getForJoint(final Integer osceletonUserId, final UserServiceCollectionResponder responder) {
90  		final User storedUser = this.get(osceletonUserId);
91  		if(storedUser != null) {
92  			return storedUser;
93  		}
94  		
95  		// artificially invoke one state step before; this is a common case.
96  		return responder.lookupProcessingUser(osceletonUserId);
97  	}
98  
99  	/** Artificially drop out users (will dispatch events to listeners). */
100 	private void clearUsers(final Collection<User> usersToBeEmptied, final UserServiceCollectionResponder responder) {
101 		// avoid concurrent modification
102 		final Collection<User> usersToBeEmptiedCopy = new ArrayList<User>(usersToBeEmptied);
103 		
104 		for (final User currentProccessing : usersToBeEmptiedCopy) {
105 			// ignore result, as just want to fake artificial logout
106 			responder.lookupDeadUser(Integer.valueOf(currentProccessing.getOsceletonId()));
107 		}
108 // MINOR assert usersToBeEmptied.isEmpty() == true : "Remaining users: " + Arrays.toString(usersToBeEmptied.toArray());
109 	}
110 
111 }