All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.mkopylec.sessioncouchbase.core.CouchbaseSession Maven / Gradle / Ivy

package com.github.mkopylec.sessioncouchbase.core;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.slf4j.Logger;
import org.springframework.session.ExpiringSession;

import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import static java.lang.System.currentTimeMillis;
import static java.util.Collections.unmodifiableSet;
import static java.util.UUID.randomUUID;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.stream.Collectors.toSet;
import static org.apache.commons.lang3.StringUtils.removeStart;
import static org.slf4j.LoggerFactory.getLogger;
import static org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME;
import static org.springframework.util.Assert.hasText;
import static org.springframework.util.Assert.isTrue;

public class CouchbaseSession implements ExpiringSession, Serializable {

    private static final long serialVersionUID = 1L;

    public static final String CREATION_TIME_ATTRIBUTE = "$creationTime";
    public static final String LAST_ACCESSED_TIME_ATTRIBUTE = "$lastAccessedTime";
    public static final String MAX_INACTIVE_INTERVAL_ATTRIBUTE = "$maxInactiveInterval";
    protected static final String GLOBAL_ATTRIBUTE_NAME_PREFIX = CouchbaseSession.class.getName() + ".global.";

    private static final Logger log = getLogger(CouchbaseSession.class);

    protected String id = randomUUID().toString();
    protected Map globalAttributesToUpdate = new HashMap<>();
    protected Set globalAttributesToRemove = new HashSet<>();
    protected Map globalAttributes = new HashMap<>();
    protected Map namespaceAttributesToUpdate = new HashMap<>();
    protected Set namespaceAttributesToRemove = new HashSet<>();
    protected Map namespaceAttributes = new HashMap<>();
    protected boolean principalSessionsUpdateRequired = false;

    public CouchbaseSession(int timeoutInSeconds) {
        long now = currentTimeMillis();
        setCreationTime(now);
        setLastAccessedTime(now);
        setMaxInactiveIntervalInSeconds(timeoutInSeconds);
    }

    public CouchbaseSession(String id, Map globalAttributes, Map namespaceAttributes) {
        this.id = id;
        this.globalAttributes = globalAttributes == null ? new HashMap<>() : globalAttributes;
        this.namespaceAttributes = namespaceAttributes == null ? new HashMap<>() : namespaceAttributes;
        if (containsPrincipalAttribute()) {
            principalSessionsUpdateRequired = true;
        }
    }

    public static String globalAttributeName(String attributeName) {
        return GLOBAL_ATTRIBUTE_NAME_PREFIX + attributeName;
    }

    @Override
    public long getCreationTime() {
        return getNumericGlobalAttributeValue(CREATION_TIME_ATTRIBUTE);
    }

    @Override
    public long getLastAccessedTime() {
        return getNumericGlobalAttributeValue(LAST_ACCESSED_TIME_ATTRIBUTE);
    }

    public void setLastAccessedTime(long lastAccessedTime) {
        globalAttributes.put(LAST_ACCESSED_TIME_ATTRIBUTE, lastAccessedTime);
        globalAttributesToUpdate.put(LAST_ACCESSED_TIME_ATTRIBUTE, lastAccessedTime);
    }

    @Override
    public void setMaxInactiveIntervalInSeconds(int interval) {
        globalAttributes.put(MAX_INACTIVE_INTERVAL_ATTRIBUTE, interval);
        globalAttributesToUpdate.put(MAX_INACTIVE_INTERVAL_ATTRIBUTE, interval);
    }

    @Override
    public int getMaxInactiveIntervalInSeconds() {
        return (int) globalAttributes.get(MAX_INACTIVE_INTERVAL_ATTRIBUTE);
    }

    @Override
    public boolean isExpired() {
        return getMaxInactiveIntervalInSeconds() >= 0 && currentTimeMillis() - SECONDS.toMillis(getMaxInactiveIntervalInSeconds()) >= getLastAccessedTime();
    }

    @Override
    public String getId() {
        return id;
    }

    @SuppressWarnings("unchecked")
    @Override
    public  T getAttribute(String attributeName) {
        checkAttributeName(attributeName);
        T attribute;
        if (isGlobal(attributeName)) {
            String name = getNameFromGlobalName(attributeName);
            attribute = (T) globalAttributes.get(name);
            log.trace("Global HTTP session attribute: [name='{}', value={}] has been read", name, attribute);
        } else {
            attribute = (T) namespaceAttributes.get(attributeName);
            log.trace("Application namespace HTTP session attribute: [name='{}', value={}] has been read", attributeName, attribute);
        }
        return attribute;
    }

    @Override
    public Set getAttributeNames() {
        Set attributesNames = globalAttributes.keySet().stream()
                .map(CouchbaseSession::globalAttributeName)
                .collect(toSet());
        attributesNames.addAll(namespaceAttributes.keySet());
        return unmodifiableSet(attributesNames);
    }

    @Override
    public void setAttribute(String attributeName, Object attributeValue) {
        checkAttributeName(attributeName);
        if (isGlobal(attributeName)) {
            String name = getNameFromGlobalName(attributeName);
            if (PRINCIPAL_NAME_INDEX_NAME.equals(name)) {
                principalSessionsUpdateRequired = true;
            }
            globalAttributes.put(name, attributeValue);
            globalAttributesToUpdate.put(name, attributeValue);
            log.trace("Global HTTP session attribute: [name='{}', value={}] has been set", name, attributeValue);
        } else {
            if (PRINCIPAL_NAME_INDEX_NAME.equals(attributeName)) {
                principalSessionsUpdateRequired = true;
            }
            namespaceAttributes.put(attributeName, attributeValue);
            namespaceAttributesToUpdate.put(attributeName, attributeValue);
            log.trace("Application namespace HTTP session attribute: [name='{}', value={}] has been set", attributeName, attributeValue);
        }
    }

    @Override
    public void removeAttribute(String attributeName) {
        checkAttributeName(attributeName);
        if (isGlobal(attributeName)) {
            String name = getNameFromGlobalName(attributeName);
            globalAttributes.remove(name);
            globalAttributesToRemove.add(name);
            log.trace("Global HTTP session attribute: [name='{}'] has been removed", name);
        } else {
            namespaceAttributes.remove(attributeName);
            namespaceAttributesToRemove.add(attributeName);
            log.trace("Application namespace HTTP session attribute: [name='{}'] has been removed", attributeName);
        }
    }

    public Map getGlobalAttributesToUpdate() {
        return globalAttributesToUpdate;
    }

    public Set getGlobalAttributesToRemove() {
        return globalAttributesToRemove;
    }

    public void clearChangedGlobalAttributes() {
        globalAttributesToUpdate.clear();
        globalAttributesToRemove.clear();
    }

    public Map getGlobalAttributes() {
        return globalAttributes;
    }

    public Map getNamespaceAttributesToUpdate() {
        return namespaceAttributesToUpdate;
    }

    public Set getNamespaceAttributesToRemove() {
        return namespaceAttributesToRemove;
    }

    public void clearChangedNamespaceAttributes() {
        namespaceAttributesToUpdate.clear();
        namespaceAttributesToRemove.clear();
    }

    public Map getNamespaceAttributes() {
        return namespaceAttributes;
    }

    public boolean isGlobalPersistenceRequired() {
        return MapUtils.isNotEmpty(globalAttributesToUpdate) || CollectionUtils.isNotEmpty(globalAttributesToRemove);
    }

    public boolean isNamespacePersistenceRequired() {
        return MapUtils.isNotEmpty(namespaceAttributesToUpdate) || CollectionUtils.isNotEmpty(namespaceAttributesToRemove);
    }

    public boolean isPrincipalSessionsUpdateRequired() {
        return principalSessionsUpdateRequired;
    }

    public String getPrincipalAttribute() {
        Object principal = globalAttributes.get(PRINCIPAL_NAME_INDEX_NAME);
        if (principal == null) {
            principal = namespaceAttributes.get(PRINCIPAL_NAME_INDEX_NAME);
        }
        return (String) principal;
    }

    public void unsetPrincipalSessionsUpdateRequired() {
        principalSessionsUpdateRequired = false;
    }

    protected void setCreationTime(long creationTime) {
        globalAttributes.put(CREATION_TIME_ATTRIBUTE, creationTime);
        globalAttributesToUpdate.put(CREATION_TIME_ATTRIBUTE, creationTime);
    }

    protected void checkAttributeName(String attributeName) {
        hasText(attributeName, "Empty HTTP session attribute name");
        isTrue(!attributeName.trim().equals(GLOBAL_ATTRIBUTE_NAME_PREFIX), "Empty HTTP session global attribute name");
    }

    protected boolean isGlobal(String attributeName) {
        return attributeName.startsWith(GLOBAL_ATTRIBUTE_NAME_PREFIX);
    }

    protected String getNameFromGlobalName(String globalAttributeName) {
        return removeStart(globalAttributeName, GLOBAL_ATTRIBUTE_NAME_PREFIX);
    }

    protected boolean containsPrincipalAttribute() {
        return globalAttributes.containsKey(PRINCIPAL_NAME_INDEX_NAME) || namespaceAttributes.containsKey(PRINCIPAL_NAME_INDEX_NAME);
    }

    protected long getNumericGlobalAttributeValue(String attributeName) {
        return ((Number) globalAttributes.get(attributeName)).longValue();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy