package com.vtence.molecule.session;
import com.vtence.molecule.Request;
import java.io.Serializable;
import java.time.Instant;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class Session implements Serializable {
private final String id;
private final Map<String, Object> attributes = new ConcurrentHashMap<>();
private Instant createdAt = Instant.now();
private Instant updatedAt = Instant.now();
private boolean invalid;
private int maxAge = -1;
public Session() {
this(null);
}
public Session(String id) {
this.id = id;
}
public static Session get(Request request) {
return request.attribute(Session.class);
}
public void bind(Request request) {
request.attribute(Session.class, this);
}
public static void unbind(Request request) {
request.removeAttribute(Session.class);
}
public String id() {
return id;
}
public boolean fresh() {
return id == null;
}
public Instant createdAt() {
return createdAt;
}
public void createdAt(Instant pointInTime) {
createdAt = pointInTime;
}
public Instant updatedAt() {
return updatedAt;
}
public void updatedAt(Instant pointInTime) {
updatedAt = pointInTime;
}
public int maxAge() {
return maxAge;
}
public void maxAge(int seconds) {
maxAge = seconds;
}
public Instant expirationTime() {
return expires() ? updatedAt.plusSeconds(maxAge) : Instant.MAX;
}
public boolean expires() {
return maxAge >= 0;
}
public boolean expired(Instant instant) {
return expires() && !instant.isBefore(expirationTime());
}
public int size() {
return attributes.size();
}
public boolean isEmpty() {
return attributes.isEmpty();
}
public boolean contains(Object key) {
return attributes.containsKey(String.valueOf(key));
}
@SuppressWarnings("unchecked")
public <T> T get(Object key) {
return (T) attributes.get(String.valueOf(key));
}
@SuppressWarnings("unchecked")
public <T> T put(Object key, Object value) {
checkValid();
return (T) attributes.put(String.valueOf(key), value);
}
@SuppressWarnings("unchecked")
public <T> T remove(Object key) {
checkValid();
return (T) attributes.remove(String.valueOf(key));
}
private void checkValid() {
if (invalid) throw new IllegalStateException("Session invalidated");
}
public Set<String> keys() {
return Collections.unmodifiableSet(attributes.keySet());
}
public Collection<Object> values() {
return Collections.unmodifiableCollection(attributes.values());
}
public void clear() {
this.attributes.clear();
}
public void merge(Session other) {
for (Object key : other.keys()) {
put(key, other.get(key));
}
}
public void invalidate() {
clear();
invalid = true;
}
public boolean invalid() {
return invalid;
}
}