![JAR search and dependency download from the Maven repository](/logo.png)
net.officefloor.web.session.HttpSessionManagedObject Maven / Gradle / Ivy
/*
* OfficeFloor - http://www.officefloor.net
* Copyright (C) 2005-2018 Daniel Sagenschneider
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package net.officefloor.web.session;
import java.io.Serializable;
import java.net.HttpCookie;
import java.time.Instant;
import java.util.Iterator;
import java.util.Map;
import net.officefloor.frame.api.build.Indexed;
import net.officefloor.frame.api.managedobject.AsynchronousContext;
import net.officefloor.frame.api.managedobject.AsynchronousManagedObject;
import net.officefloor.frame.api.managedobject.CoordinatingManagedObject;
import net.officefloor.frame.api.managedobject.ManagedObject;
import net.officefloor.frame.api.managedobject.ObjectRegistry;
import net.officefloor.frame.api.managedobject.ProcessAwareContext;
import net.officefloor.frame.api.managedobject.ProcessAwareManagedObject;
import net.officefloor.server.http.HttpRequest;
import net.officefloor.server.http.HttpRequestCookie;
import net.officefloor.server.http.HttpResponse;
import net.officefloor.server.http.ServerHttpConnection;
import net.officefloor.web.session.spi.CreateHttpSessionOperation;
import net.officefloor.web.session.spi.FreshHttpSession;
import net.officefloor.web.session.spi.HttpSessionIdGenerator;
import net.officefloor.web.session.spi.HttpSessionStore;
import net.officefloor.web.session.spi.InvalidateHttpSessionOperation;
import net.officefloor.web.session.spi.RetrieveHttpSessionOperation;
import net.officefloor.web.session.spi.StoreHttpSessionOperation;
/**
* {@link ManagedObject} for a {@link HttpSession}.
*
* @author Daniel Sagenschneider
*/
public class HttpSessionManagedObject
implements CoordinatingManagedObject, AsynchronousManagedObject, ProcessAwareManagedObject {
/**
* Use epoch to expire cookies.
*/
private static final Instant EXPIRE_COOKIE_INSTANT = Instant.EPOCH;
/**
* {@link HttpSession} to be provided as the object of this
* {@link ManagedObject}.
*/
private final HttpSessionImpl session = new HttpSessionImpl();
/**
* Name of the {@link HttpCookie} containing the Session Id.
*/
private final String sessionIdCookieName;
/**
* Index of the dependency {@link ServerHttpConnection}.
*/
private final int serverHttpConnectionIndex;
/**
* Index of the dependency {@link HttpSessionIdGenerator}.
*/
private final int httpSessionIdGeneratorIndex;
/**
* {@link HttpSessionIdGenerator}.
*/
private HttpSessionIdGenerator httpSessionIdGenerator;
/**
* Index of the dependency {@link HttpSessionStore}.
*/
private final int httpSessionStoreIndex;
/**
* {@link HttpSessionStore}.
*/
private HttpSessionStore httpSessionStore;
/**
* {@link AsynchronousContext}.
*/
private AsynchronousContext asynchronousContext;
/**
* {@link ProcessAwareContext}.
*/
private ProcessAwareContext processAwareContext;
/**
* {@link ServerHttpConnection}.
*/
private ServerHttpConnection connection;
/**
* Flag indicating if waiting on an asynchronous operation.
*/
private boolean isWaiting = false;
/**
* Flag indicating if the Session Id has been loaded.
*/
private boolean isIdLoaded = false;
/**
* Flag indicating if the Session has been loaded.
*/
private boolean isSessionLoaded = false;
/**
* Flag indicating if invalidating the {@link HttpSession}.
*/
private boolean isInvalidating = false;
/**
* Flag indicating if storing the {@link HttpSession}.
*/
private boolean isStoring = false;
/**
* Failure in loading the {@link HttpSession}.
*/
private Throwable failure = null;
/**
* Session Id.
*/
private String sessionId = null;
/**
* Flag indicating if the {@link HttpSession} is new.
*/
private boolean isNewSession = false;
/**
* Initiate.
*
* @param sessionIdCookieName
* Name of the {@link HttpCookie} containing the Session Id.
* @param serverHttpConnectionIndex
* Index of the dependency {@link ServerHttpConnection}.
* @param httpSessionIdGeneratorIndex
* Index of the dependency {@link HttpSessionIdGenerator}.
* @param httpSessionIdGenerator
* {@link HttpSessionIdGenerator}. null
to obtain
* via dependency.
* @param httpSessionStoreIndex
* Index of the dependency {@link HttpSessionStore}.
* @param httpSessionStore
* {@link HttpSessionStore}. null
to obtain via
* dependency.
*/
public HttpSessionManagedObject(String sessionIdCookieName, int serverHttpConnectionIndex,
int httpSessionIdGeneratorIndex, HttpSessionIdGenerator httpSessionIdGenerator, int httpSessionStoreIndex,
HttpSessionStore httpSessionStore) {
this.sessionIdCookieName = sessionIdCookieName;
this.serverHttpConnectionIndex = serverHttpConnectionIndex;
this.httpSessionIdGeneratorIndex = httpSessionIdGeneratorIndex;
this.httpSessionIdGenerator = httpSessionIdGenerator;
this.httpSessionStoreIndex = httpSessionStoreIndex;
this.httpSessionStore = httpSessionStore;
}
/**
* Generates the Session Id.
*/
private void generateSessionId() {
// As generating, no Session or Id loaded
this.isIdLoaded = false;
this.isSessionLoaded = false;
// Flag that no longer invalidating as generating Session
this.isInvalidating = false;
// Trigger generating the Session Id
this.httpSessionIdGenerator.generateSessionId(new FreshHttpSessionImpl(this.connection));
// Check if Session Id immediately generated
if (!this.isIdLoaded) {
// Session Id not loaded so wait until loaded
this.flagWaiting();
}
}
/**
* Loads the Session Id and continues processing loading the
* {@link HttpSession}.
*
* @param sessionId
* Session Id.
* @param isNewSession
* Flag indicating if a new {@link HttpSession}.
*/
private void loadSessionId(String sessionId, boolean isNewSession) {
this.isIdLoaded = true;
this.sessionId = sessionId;
this.isNewSession = isNewSession;
// As Id just generated, no Session loaded
this.isSessionLoaded = false;
// Handle based on whether a new session
if (isNewSession) {
// Create the session within the store
this.httpSessionStore.createHttpSession(new CreateHttpSessionOperationImpl(this.sessionId));
} else {
// Retrieve the session from the store
this.httpSessionStore.retrieveHttpSession(new RetrieveHttpSessionOperationImpl(this.sessionId));
}
// Determine if the session loaded
if (!this.isSessionLoaded) {
// Wait until the session is loaded
this.flagWaiting();
}
}
/**
* Loads the {@link HttpSession}.
*
* @param creationTime
* Creation Time.
* @param expireTime
* Time to expire the {@link HttpSession} should it be idle.
* @param attributes
* {@link HttpSession} Attributes.
*/
private void loadSession(Instant creationTime, Instant expireTime, Map attributes) {
this.isSessionLoaded = true;
// Load state of session
this.session.loadState(this.sessionId, creationTime, expireTime, this.isNewSession, attributes);
// Add cookie to maintain Session Id by client
this.setSessionIdCookieToHttpResponse(this.sessionId, expireTime);
// Flag completed load of the Session
this.flagComplete();
}
/**
* Triggers storing the {@link HttpSession}.
*
* @param sessionId
* Session Id.
* @param creationTime
* Creation time.
* @param expireTime
* Time to expire the {@link HttpSession} should it be idle.
* @param attributes
* Attributes.
* @throws Throwable
* If immediate failure in storing Session.
*/
private void storeSession(String sessionId, Instant creationTime, Instant expireTime,
Map attributes) throws Throwable {
// Trigger storing the session
this.isStoring = true;
this.httpSessionStore
.storeHttpSession(new StoreHttpSessionOperationImpl(sessionId, creationTime, expireTime, attributes));
// Determine if stored immediately
if (this.isStoring) {
// Not stored immediately so wait until stored
this.flagWaiting();
}
// Propagate immediate failure to store
if (this.failure != null) {
throw this.failure;
}
}
/**
* Flags the storing of the {@link HttpSession} is complete.
*/
private void storeComplete() {
// Flag no longer storing Session
this.isStoring = false;
this.flagComplete();
}
/**
* Triggers invalidating the {@link HttpSession}.
*
* @param isRequireNewSession
* Flag indicating if requires a new {@link HttpSession}.
*/
private void invalidateSession(boolean isRequireNewSession) {
// No longer loaded
this.isIdLoaded = false;
this.isSessionLoaded = false;
// Flag invalid if not creating another session
if (!isRequireNewSession) {
// Capture the session
String sessionId = this.session.sessionId;
// Invalidate the Session
this.session.invalidate(null);
// Add expired cookie to remove Session Id.
// (If creating new Session will add appropriate Cookie)
this.setSessionIdCookieToHttpResponse(sessionId, EXPIRE_COOKIE_INSTANT);
}
// Trigger invalidating the session
this.isInvalidating = true;
this.httpSessionStore
.invalidateHttpSession(new InvalidateHttpSessionOperationImpl(this.sessionId, isRequireNewSession));
// Determine if invalidated immediately
if (this.isInvalidating) {
// Not invalidated immediately so wait until invalidated
this.flagWaiting();
}
}
/**
* Flags the invalidation of the {@link HttpSession} is complete.
*/
private void invalidateComplete() {
// Flag no longer invalidating Session
this.isInvalidating = false;
this.flagComplete();
}
/**
* Loads failure.
*
* @param cause
* Cause of the failure.
*/
private void loadFailure(Throwable cause) {
this.failure = cause;
// Flag loaded (as no further loading on failure)
this.isIdLoaded = true;
this.isSessionLoaded = true;
// Flag session invalid
this.session.invalidate(cause);
// No longer invalidating due to error
this.isInvalidating = false;
// Flag operation complete as failed
this.flagComplete();
}
/**
* Flags that waiting on asynchronous operation.
*/
private void flagWaiting() {
// Only notify once that waiting (if no failure)
if ((!this.isWaiting) && (this.failure == null)) {
// Flat to wait as not yet waiting
this.isWaiting = true;
this.asynchronousContext.start(null);
}
}
/**
* Flags that complete operation and no longer required to wait.
*/
private void flagComplete() {
// Only notify complete if waiting
if (this.isWaiting) {
this.asynchronousContext.complete(null);
this.isWaiting = false;
}
}
/**
* Indicates if operation is complete (in other words that can use the
* {@link HttpSession}).
*
* @return true
if can complete the {@link HttpSession}.
* @throws Throwable
* If failure in operation.
*/
private boolean isOperationComplete() throws Throwable {
// Propagate potential failure
if (this.failure != null) {
throw this.failure;
}
// Not complete if waiting
return (!this.isWaiting);
}
/**
* Adds the Session Id {@link HttpCookie} to the {@link HttpResponse}.
*
* @param sessionId
* Session Id.
* @param expireTime
* Time that the {@link HttpCookie} is to expire.
*/
private void setSessionIdCookieToHttpResponse(String sessionId, Instant expireTime) {
this.connection.getResponse().getCookies().setCookie(this.sessionIdCookieName, sessionId,
(cookie) -> cookie.setExpires(expireTime));
}
/*
* ================ AsynchronousManagedObject ===========================
*/
@Override
public void setAsynchronousContext(AsynchronousContext asynchronousContext) {
this.asynchronousContext = asynchronousContext;
}
/*
* ================ ProcessAwareManagedObject ===========================
*/
@Override
public void setProcessAwareContext(ProcessAwareContext context) {
this.processAwareContext = context;
}
/*
* ================ CoordinatingManagedObject ===========================
*/
@Override
public void loadObjects(ObjectRegistry registry) throws Throwable {
// Obtain the HTTP request
this.connection = (ServerHttpConnection) registry.getObject(this.serverHttpConnectionIndex);
HttpRequest request = this.connection.getRequest();
// Ensure have the HTTP session Id generator
if (this.httpSessionIdGenerator == null) {
this.httpSessionIdGenerator = (HttpSessionIdGenerator) registry.getObject(this.httpSessionIdGeneratorIndex);
}
// Ensure have the HTTP session store
if (this.httpSessionStore == null) {
this.httpSessionStore = (HttpSessionStore) registry.getObject(this.httpSessionStoreIndex);
}
// Obtain the Session Id from the Session cookie
HttpRequestCookie sessionIdCookie = request.getCookies().getCookie(this.sessionIdCookieName);
String sessionId = (sessionIdCookie == null ? null : sessionIdCookie.getValue());
// Handle based on Session Id being available
if ((sessionId == null) || (sessionId.trim().length() == 0)) {
// No established session so create a new session
this.generateSessionId();
} else {
// Retrieve the existing session
this.loadSessionId(sessionId, false);
}
}
/*
* ======================== ManagedObject ================================
*/
@Override
public Object getObject() throws Throwable {
// Propagate failure in obtaining Http Session
if (this.failure != null) {
throw this.failure;
}
// No failure so return the Http Session
return this.session;
}
/**
* {@link HttpSession} and {@link HttpSessionAdministration} implementation.
*/
private class HttpSessionImpl implements HttpSession, HttpSessionAdministration {
/**
* Session Id.
*/
private String sessionId;
/**
* Creation time of the {@link HttpSession}.
*/
private Instant creationTime;
/**
* Time to expire the {@link HttpSession} should it be idle.
*/
private Instant expireTime;
/**
* Indicates if this {@link HttpSession} is new.
*/
private boolean isNew;
/**
* Attributes of the {@link HttpSession}.
*/
private Map attributes;
/**
* Flag indicating if this {@link HttpSession} is invalid.
*/
private boolean isInvalid = true;
/**
* Failure in invalidating this {@link HttpSession}.
*/
private Throwable invalidateFailure = null;
/**
* Loads the state of this {@link HttpSession}.
*
* @param sessionId
* Session Id.
* @param creationTime
* Creation time.
* @param expireTime
* Time to expire the {@link HttpSession} should it be idle.
* @param isNew
* If a new {@link HttpSession}.
* @param attributes
* Attributes.
*/
private void loadState(String sessionId, Instant creationTime, Instant expireTime, boolean isNew,
Map attributes) {
// Load state
this.sessionId = sessionId;
this.creationTime = creationTime;
this.expireTime = expireTime;
this.isNew = isNew;
this.attributes = attributes;
// Now valid HTTP session
this.isInvalid = false;
}
/**
* Flags this {@link HttpSession} as invalid.
*
* @param failure
* Potential failure invalidating this {@link HttpSession}.
* May be null
.
*/
private void invalidate(Throwable failure) {
this.isInvalid = true;
this.invalidateFailure = failure;
}
/**
* Ensures {@link HttpSession} is valid for use.
*
* @throws InvalidatedSessionHttpException
* If {@link HttpSession} is not valid for use.
*/
private void ensureValid() throws InvalidatedSessionHttpException {
// Not valid if:
// - invalid
// - currently invalidating
if (this.isInvalid || HttpSessionManagedObject.this.isInvalidating) {
throw new InvalidatedSessionHttpException(this.invalidateFailure);
}
}
/**
* Ensures can alter the {@link HttpSession}.
*
* @throws StoringSessionHttpException
* If not able to alter the {@link HttpSession}.
*/
private void ensureCanAlter() throws StoringSessionHttpException {
if (HttpSessionManagedObject.this.isStoring) {
throw new StoringSessionHttpException();
}
}
/*
* ================ HttpSession ===============================
*/
@Override
public String getSessionId() {
return HttpSessionManagedObject.this.processAwareContext.run(() -> {
this.ensureValid();
return this.sessionId;
});
}
@Override
public String getTokenName() {
return HttpSessionManagedObject.this.processAwareContext
.run(() -> HttpSessionManagedObject.this.sessionIdCookieName);
}
@Override
public Instant getCreationTime() {
return HttpSessionManagedObject.this.processAwareContext.run(() -> {
this.ensureValid();
return this.creationTime;
});
}
@Override
public Instant getExpireTime() throws InvalidatedSessionHttpException {
return HttpSessionManagedObject.this.processAwareContext.run(() -> {
this.ensureValid();
return this.expireTime;
});
}
@Override
public void setExpireTime(Instant expireTime)
throws StoringSessionHttpException, InvalidatedSessionHttpException {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
this.ensureValid();
this.ensureCanAlter();
// Update expiring of Session Id (and its cookie)
this.expireTime = expireTime;
HttpSessionManagedObject.this.setSessionIdCookieToHttpResponse(this.sessionId, this.expireTime);
// Void return
return null;
});
}
@Override
public boolean isNew() {
return HttpSessionManagedObject.this.processAwareContext.run(() -> {
this.ensureValid();
return this.isNew;
});
}
@Override
public Serializable getAttribute(String name) {
return HttpSessionManagedObject.this.processAwareContext.run(() -> {
this.ensureValid();
return this.attributes.get(name);
});
}
@Override
public Iterator getAttributeNames() {
return HttpSessionManagedObject.this.processAwareContext.run(() -> {
this.ensureValid();
return this.attributes.keySet().iterator();
});
}
@Override
public void setAttribute(String name, Serializable object) {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
this.ensureValid();
this.ensureCanAlter();
this.attributes.put(name, object);
return null;
});
}
@Override
public void removeAttribute(String name) {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
this.ensureValid();
this.ensureCanAlter();
this.attributes.remove(name);
return null;
});
}
@Override
public HttpSessionAdministration getHttpSessionAdministration() {
return this;
}
/*
* ================== HttpSessionAdministration =======================
*/
@Override
public void invalidate(boolean isRequireNewSession) throws Throwable {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
HttpSessionManagedObject.this.invalidateSession(isRequireNewSession);
return null;
});
}
@Override
public void store() throws Throwable {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
HttpSessionManagedObject.this.storeSession(this.sessionId, this.creationTime, this.expireTime,
this.attributes);
return null;
});
}
@Override
public boolean isOperationComplete() throws Throwable {
return HttpSessionManagedObject.this.processAwareContext
.run(() -> HttpSessionManagedObject.this.isOperationComplete());
}
}
/**
* {@link FreshHttpSession} implementation.
*/
private class FreshHttpSessionImpl implements FreshHttpSession {
/**
* {@link ServerHttpConnection}.
*/
private final ServerHttpConnection connection;
/**
* Initiate.
*
* @param connection
* {@link ServerHttpConnection}.
*/
public FreshHttpSessionImpl(ServerHttpConnection connection) {
this.connection = connection;
}
/*
* ================= FreshHttpSession ===========================
*/
@Override
public ServerHttpConnection getConnection() {
return this.connection;
}
@Override
public void setSessionId(String sessionId) {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
HttpSessionManagedObject.this.loadSessionId(sessionId, true);
return null;
});
}
@Override
public void failedToGenerateSessionId(Throwable failure) {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
HttpSessionManagedObject.this.loadFailure(failure);
return null;
});
}
}
/**
* {@link CreateHttpSessionOperation} implementation.
*/
private class CreateHttpSessionOperationImpl implements CreateHttpSessionOperation {
/**
* Session Id.
*/
private final String sessionId;
/**
* Initiate.
*
* @param sessionId
* Session Id.
*/
public CreateHttpSessionOperationImpl(String sessionId) {
this.sessionId = sessionId;
}
/*
* ============= CreateHttpSessionOperation ====================
*/
@Override
public String getSessionId() {
return this.sessionId;
}
@Override
public void sessionCreated(Instant creationTime, Instant expireTime, Map attributes) {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
HttpSessionManagedObject.this.loadSession(creationTime, expireTime, attributes);
return null;
});
}
@Override
public void sessionIdCollision() {
// Generate a new Session Id
HttpSessionManagedObject.this.processAwareContext.run(() -> {
HttpSessionManagedObject.this.generateSessionId();
return null;
});
}
@Override
public void failedToCreateSession(Throwable cause) {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
HttpSessionManagedObject.this.loadFailure(cause);
return null;
});
}
}
/**
* {@link RetrieveHttpSessionOperation} implementation.
*/
private class RetrieveHttpSessionOperationImpl implements RetrieveHttpSessionOperation {
/**
* Session Id.
*/
private final String sessionId;
/**
* Initiate.
*
* @param sessionId
* Session Id.
*/
public RetrieveHttpSessionOperationImpl(String sessionId) {
this.sessionId = sessionId;
}
/*
* ================ RetrieveHttpSessionOperation ===================
*/
@Override
public String getSessionId() {
return this.sessionId;
}
@Override
public void sessionRetrieved(Instant creationTime, Instant expireTime, Map attributes) {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
HttpSessionManagedObject.this.loadSession(creationTime, expireTime, attributes);
return null;
});
}
@Override
public void sessionNotAvailable() {
// Session not available so generate new Session
HttpSessionManagedObject.this.processAwareContext.run(() -> {
HttpSessionManagedObject.this.generateSessionId();
return null;
});
}
@Override
public void failedToRetreiveSession(Throwable cause) {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
HttpSessionManagedObject.this.loadFailure(cause);
return null;
});
}
}
/**
* {@link StoreHttpSessionOperation} implementation.
*/
private class StoreHttpSessionOperationImpl implements StoreHttpSessionOperation {
/**
* Session Id.
*/
private final String sessionId;
/**
* Creation time.
*/
private final Instant creationTime;
/**
* Expire time.
*/
private final Instant expireTime;
/**
* Attributes.
*/
private final Map attributes;
/**
* Initiate.
*
* @param sessionId
* Session Id.
* @param creationTime
* Creation time.
* @param expireTime
* Time to expire the {@link HttpSession} should it be idle.
* @param attributes
* Attributes.
*/
public StoreHttpSessionOperationImpl(String sessionId, Instant creationTime, Instant expireTime,
Map attributes) {
this.sessionId = sessionId;
this.creationTime = creationTime;
this.expireTime = expireTime;
this.attributes = attributes;
}
/*
* ============= StoreHttpSessionOperation ==========================
*/
@Override
public String getSessionId() {
return this.sessionId;
}
@Override
public Instant getCreationTime() {
return this.creationTime;
}
@Override
public Instant getExpireTime() {
return this.expireTime;
}
@Override
public Map getAttributes() {
return this.attributes;
}
@Override
public void sessionStored() {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
HttpSessionManagedObject.this.storeComplete();
return null;
});
}
@Override
public void failedToStoreSession(Throwable cause) {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
HttpSessionManagedObject.this.loadFailure(cause);
return null;
});
}
}
/**
* {@link InvalidateHttpSessionOperation} implementation.
*/
private class InvalidateHttpSessionOperationImpl implements InvalidateHttpSessionOperation {
/**
* Session Id.
*/
private final String sessionId;
/**
* Flag indicating if require a new {@link HttpSession}.
*/
private final boolean isRequireNewSession;
/**
* Initiate.
*
* @param sessionId
* Session Id.
* @param isRequireNewSession
* Flag indicating if require a new {@link HttpSession}.
*/
public InvalidateHttpSessionOperationImpl(String sessionId, boolean isRequireNewSession) {
this.sessionId = sessionId;
this.isRequireNewSession = isRequireNewSession;
}
/*
* ============== InvalidateHttpSessionOperation =====================
*/
@Override
public String getSessionId() {
return this.sessionId;
}
@Override
public void sessionInvalidated() {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
if (this.isRequireNewSession) {
// Generate a new Session as required
HttpSessionManagedObject.this.generateSessionId();
} else {
// Flag invalidate complete, leaving Session invalid
HttpSessionManagedObject.this.invalidateComplete();
}
return null;
});
}
@Override
public void failedToInvalidateSession(Throwable cause) {
HttpSessionManagedObject.this.processAwareContext.run(() -> {
HttpSessionManagedObject.this.loadFailure(cause);
return null;
});
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy