How to add, and remove HashMap values by insertion order?

943 views Asked by At

I would like to know how I could map the users that connect based on their unique id's and id session so that when there are more than 3 sessions for that id, the users who connected first are removed from the hashmap and so on.

Example:

UserID:3 Session:1980002
UserID:3 Session:2841111
UserID:3 Session:84848

The UserID already contains 3 active sessions, the oldest one is removed and the KillSession invoked, giving way to new.

UserID:3 Session:2841111
UserID:3 Session:84848
UserID:3 Session:4848880

Code:

public void onHTTPCupertinoStreamingSessionCreate(HTTPStreamerSessionCupertino httpSession) {
    String User_Session = httpSession.getSessionId();
    String Client_ID = httpSession.getProperties().getPropertyStr("sql_client_id");
    /* Verifies that there are already 3 active sessions and removes the oldest, 
    since the limit of simultaneous sessions is 3 for each user,
    and add to hashmap, Client_ID and User_Session */
}

public void onHTTPCupertinoStreamingSessionDestroy(IHTTPStreamerSession httpSession) {
    String User_Session = httpSession.getSessionId();
    //remove from hashmap, Client_ID based on session User_Session
}

public void KillSession(int SessionId){ 
    IApplicationInstance Instance = applicationInstance;
    IHTTPStreamerSession sessions = Instance.getHTTPStreamerSessions().get(SessionId);
    sessions.rejectSession();
    //remove from hashmap, Client_ID based on session User_Session
}

The Client_ID is the id of the user in the database, the User_Session is the unique session in the wowza generated for each connection, this session does not have equal values, that is, if the same Client_ID connects more than once, that value will be different For each of your sessions.

That is, basically my difficulty is to mount the hashmap, how could I do this?

2

There are 2 answers

0
Anonymous On

If I have understood correctly that you want to store up to three session IDs per user/client ID, I don’t really think that a LinkedHashMap will help you. It is correct that a LinkedHashMap maintains insertion order, as opposed to a HashMap.

I have a different suggestion for you. To keep things separate, I suggest this little auxiliary class to hold the map:

public class MapOfSessions {

    private Map<String, Queue<Integer>> sessionMap = new HashMap<>();

    public int countSessions(String clientId) {
        Queue<Integer> q = sessionMap.get(clientId);
        if (q == null) {
            return 0;
        } else {
            return q.size();
        }
    }

    public int removeOldestSession(String clientId) {
        return sessionMap.get(clientId).remove();
    }

    public void add(String clientId, int sessionId) {
        Queue<Integer> q = sessionMap.get(clientId);
        if (q == null) {
            q = new ArrayDeque<>();
            sessionMap.put(clientId, q);
        }
        q.add(sessionId);
    }

    public void remove(String clientId, int sessionId) {
        sessionMap.get(clientId).remove(sessionId);
        // if queue is now empty, may remove key from map
    }
}

Now the map is what keeps the correspondenace between client ID and session ID, while the Queue is keeping the insertion order.

With this you may solve your task in the following way. I have taken the removal from the map out of killSession() and have given that responibility to the caller, onHTTPCupertinoStreamingSessionCreate().

private int maxSessionsPerUser = 3;
private MapOfSessions sessionsPerUser = new MapOfSessions();

public void onHTTPCupertinoStreamingSessionCreate(HTTPStreamerSessionCupertino httpSession) {
    // use camel case for variable names: begin with lowercase, no underscores
    String userSession = httpSession.getSessionId();
    String clientId = httpSession.getProperties().getPropertyStr("sql_client_id");
    /* Verifies that there are already 3 active sessions and removes the oldest, 
    since the limit of simultaneous sessions is 3 for each user,
    and add to hashmap, clientId and userSession */
    if (sessionsPerUser.countSessions(clientId) == maxSessionsPerUser) {
        int oldestSession = sessionsPerUser.removeOldestSession(clientId);
        killSession(oldestSession);
    }
    sessionsPerUser.add(clientId, Integer.parseInt(userSession));
}

public void onHTTPCupertinoStreamingSessionDestroy(IHTTPStreamerSession httpSession) {
    String userSession = httpSession.getSessionId();
    // it’s easier to remove from map when we know both clientId and userSession
    String clientId = httpSession.getProperties().getPropertyStr("sql_client_id");
    //remove from hashmap, clientId based on session userSession
    sessionsPerUser.remove(clientId, Integer.parseInt(userSession));
}

// method name in camel case (like variable names)
public void killSession(int SessionId){ 
    IApplicationInstance Instance = applicationInstance;
    IHTTPStreamerSession sessions = Instance.getHTTPStreamerSessions().get(SessionId);
    sessions.rejectSession();
    //don’t remove from hashmap here, assume caller has done that
}

I am storing the client ID as string and the session ID as integer. You may want to use the same type for both. Since you had declared KillSession()with an int parameter, I thought I’d use int for the session.

6
Sri On

If you want to add and remove in insertion order, use a LinkedHashMap. (A simple version of what might be of help)

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapExample {
    static class User {
        LinkedHashMap<String, Integer> sessionIds = new LinkedHashMap<>();
        int userId;

        public User(int userId) {
            this.userId = userId;
        }

        public void addSession(String someField, int sessionId) {
            this.sessionIds = new LinkedHashMap<String, Integer>(sessionIds) {
                protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {
                    return size() > 3;
                }
            };
            sessionIds.put(someField, sessionId);
        }

        @Override
        public String toString() {
            return "User{" +
                    "sessionIds=" + sessionIds +
                    ", userId=" + userId +
                    '}';
        }
    }

    public static void main(String[] args) {
        User user1 = new User(1);
        user1.addSession("1980002", 1980002);
        user1.addSession("84848", 84848);
        user1.addSession("2841111", 2841111);
        System.out.println(user1);
        user1.addSession("999999", 999999);
        System.out.println(user1);
        user1.addSession("777777", 777777);
        System.out.println(user1);
    }
}