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

org.wildfly.clustering.session.cache.ContextualSessionManager Maven / Gradle / Ivy

There is a newer version: 5.0.7.Final
Show newest version
/*
 * Copyright The WildFly Authors
 * SPDX-License-Identifier: Apache-2.0
 */

package org.wildfly.clustering.session.cache;

import java.util.Optional;
import java.util.concurrent.CompletionStage;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;

import org.wildfly.clustering.cache.batch.Batch;
import org.wildfly.clustering.cache.batch.Batcher;
import org.wildfly.clustering.server.context.Context;
import org.wildfly.clustering.server.context.ContextFactory;
import org.wildfly.clustering.server.context.Contextual;
import org.wildfly.clustering.session.ImmutableSession;
import org.wildfly.clustering.session.Session;
import org.wildfly.clustering.session.SessionManager;
import org.wildfly.clustering.session.SessionStatistics;
import org.wildfly.common.function.Functions;

/**
 * A concurrent session manager, that can share session references across concurrent threads.
 * @author Paul Ferraro
 */
public class ContextualSessionManager implements SessionManager {

	private final SessionManager manager;
	private final Context>> sessionContext;
	private final BiFunction>> sessionCreator;
	private final BiFunction>> sessionFinder;
	private final UnaryOperator> validator = new UnaryOperator<>() {
		@Override
		public Session apply(Session session) {
			// If session was invalidated by a concurrent thread, return null instead of an invalid session
			// This will reduce the likelihood that a duplicate invalidation request (e.g. from a double-clicked logout) results in an ISE
			if (session != null && !session.isValid()) {
				session.close();
				return null;
			}
			return session;
		}
	};

	public ContextualSessionManager(SessionManager manager, ContextFactory contextFactory) {
		this.manager = manager;
		this.sessionCreator = new BiFunction<>() {
			@Override
			public CompletionStage> apply(String id, Runnable closeTask) {
				return manager.createSessionAsync(id).thenApply(session -> new ContextualSessionRegistration<>(session, closeTask));
			}
		};
		Function> empty = closeTask -> {
			closeTask.run();
			return null;
		};
		this.sessionFinder = new BiFunction<>() {
			@Override
			public CompletionStage> apply(String id, Runnable closeTask) {
				return manager.findSessionAsync(id).thenApply(session -> (session != null) ? new ContextualSessionRegistration<>(session, closeTask) : empty.apply(closeTask));
			}
		};
		this.sessionContext = contextFactory.createContext(Functions.discardingConsumer(), new Consumer>>() {
			@Override
			public void accept(CompletionStage> future) {
				future.thenAccept(session -> Optional.ofNullable(session).ifPresent(Contextual::end));
			}
		});
	}

	@Override
	public CompletionStage> createSessionAsync(String id) {
		return this.sessionContext.computeIfAbsent(id, this.sessionCreator).thenApply(Function.identity());
	}

	@Override
	public CompletionStage> findSessionAsync(String id) {
		return this.sessionContext.computeIfAbsent(id, this.sessionFinder).thenApply(this.validator);
	}

	@Override
	public CompletionStage findImmutableSessionAsync(String id) {
		return this.manager.findImmutableSessionAsync(id);
	}

	@Override
	public Supplier getIdentifierFactory() {
		return this.manager.getIdentifierFactory();
	}

	@Override
	public void start() {
		this.manager.start();
	}

	@Override
	public void stop() {
		this.manager.stop();
	}

	@Override
	public Batcher getBatcher() {
		return this.manager.getBatcher();
	}

	@Override
	public SessionStatistics getStatistics() {
		return this.manager.getStatistics();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy