I'm trying to manage sessions in a simple Java application. My idea is to create a SessionManagerSingleton that instantiates the sessions and the actual Session, which holds the real information, like this:
public class SessionManagerSingleton {
private static SessionManagerSingleton instance;
private Map<String, Session> activeSessions;
private SessionManagerSingleton() {
activeSessions = new HashMap<>();
}
public static synchronized SessionManagerSingleton getInstance() {
if (instance == null) {
instance = new SessionManagerSingleton();
}
return instance;
}
public String addSession(String email) {
String sessionId = generateSessionId();
Session session = new Session(email);
activeSessions.put(sessionId, session);
return sessionId;
}
public Session getSession(String sessionId) {
return activeSessions.get(sessionId);
}
private String generateSessionId() {
return UUID.randomUUID().toString();
}
}
package com.example.wanderwisep.sessionManagement;
import java.util.UUID;
public class Session {
String email;
//Other Information
String id;
public Session(String email) {
id = generateSessionId();
this.email = email;
}
private String generateSessionId() {
String id = UUID.randomUUID().toString();
System.out.println("id sessione:");
System.out.println(id);
return id;
}
My problem is, how I can save the id for calling the getSession(String id) in another part of the code? I tried using a global variable, but this can pose issues in a multi-user application. (I know it's not a distributed application, but I would like to manage it as such).
Based on the comments, only a single user can access your application at once. In that case, it is both correct and reasonable to simply store the currently active session's ID in a global variable when the users logs in and wipe it on logout.
If the application was concurrently accessible, I'd make a couple of changes first:
Since the initializations happens when the class is loaded, and the JVM guarantees that happening once per class loader, you no longer have to worry about synchronization or volatility. And the class will be loaded on first access anyway, so this is already as lazy as it needs to be. For edge cases, you can employ the holder idiom.
This way, many threads (handling many user requests) can safely read and update the map concurrently.
With all that said, your original question remains: how to know what is the current session?
Normally, it's the client's responsibility to identify itself. E.g. when the user logs in via a (web/mobile/desktop) client application, you return the newly generated session ID to the client (perhaps in a cookie, or a custom header, or just in the response payload itself). The client (and not your server application) then stores this somewhere (a browser might store it in the local storage, or in a cookie, a mobile client might store it in the phone's Shared Preferences, a desktop client might keep it a file somewhere) and then sends it back with each subsequent request to the application. Your application can then use the ID the client sends and associate the correct session with each request. If each request is served by a separate dedicated thread (as in the traditional Servlet model), the application might also store the current session in a
ThreadLocalvariable to make it implicitly accessible from anywhere (without passing it around as an argument to each method), and clean it up at the end of the request. This is commonly handled by the framework and not the application itself.If you wanted to simulate a concurrently accessible application, you could print out or otherwise display the new session ID when a user logs in, and require that same ID to be passed to all entry points in the application. It will be cumbersome, but this is basically what a server application really does.
Does this help?