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

org.wildfly.clustering.tomcat.catalina.DistributableManager Maven / Gradle / Ivy

The newest version!
/*
 * Copyright The WildFly Authors
 * SPDX-License-Identifier: Apache-2.0
 */
package org.wildfly.clustering.tomcat.catalina;

import java.io.IOException;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;

import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;

import org.apache.catalina.Context;
import org.wildfly.clustering.cache.batch.Batch;
import org.wildfly.clustering.marshalling.Marshallability;
import org.wildfly.clustering.session.ImmutableSession;
import org.wildfly.clustering.session.Session;
import org.wildfly.clustering.session.SessionManager;
import org.wildfly.clustering.session.spec.servlet.HttpSessionProvider;

/**
 * Adapts a WildFly distributable SessionManager to Tomcat's Manager interface.
 * @author Paul Ferraro
 */
public class DistributableManager implements CatalinaManager {
	private static final char ROUTE_DELIMITER = '.';

	private final SessionManager manager;
	private final UnaryOperator affinity;
	private final Context context;
	private final Consumer invalidateAction;
	private final Marshallability marshallability;

	public DistributableManager(SessionManager manager, UnaryOperator affinity, Context context, Marshallability marshallability) {
		this.manager = manager;
		this.affinity = affinity;
		this.marshallability = marshallability;
		this.context = context;
		this.invalidateAction = new CatalinaSessionDestroyAction(context);
	}

	@Override
	public SessionManager getSessionManager() {
		return this.manager;
	}

	@Override
	public Marshallability getMarshallability() {
		return this.marshallability;
	}

	/**
	 * Strips routing information from requested session identifier.
	 */
	private static String parseSessionId(String requestedSesssionId) {
		int index = requestedSesssionId.indexOf(ROUTE_DELIMITER);
		return (index < 0) ? requestedSesssionId : requestedSesssionId.substring(0, index);
	}

	/**
	 * Appends routing information to session identifier.
	 */
	private org.apache.catalina.Session getSession(Session session, Batch batch) {
		String id = session.getId();
		String route = this.affinity.apply(id);
		String internalId = new StringBuilder(id.length() + route.length() + 1).append(id).append(ROUTE_DELIMITER).append(route).toString();
		return new DistributableSession(this, session, internalId, batch.suspend(), () -> this.invalidateAction.accept(session));
	}

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

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

	@Override
	public org.apache.catalina.Session createSession(String sessionId) {
		String id = (sessionId != null) ? parseSessionId(sessionId) : this.manager.getIdentifierFactory().get();
		boolean close = true;
		// Batch will be closed by Session.close();
		Batch batch = this.manager.getBatchFactory().get();
		try {
			Session session = this.manager.createSession(id);
			HttpSessionEvent event = new HttpSessionEvent(HttpSessionProvider.INSTANCE.asSession(session, this.context.getServletContext()));
			Stream.of(this.context.getApplicationLifecycleListeners()).filter(HttpSessionListener.class::isInstance).map(HttpSessionListener.class::cast).forEach(listener -> {
				try {
					this.context.fireContainerEvent("beforeSessionCreated", listener);
					listener.sessionCreated(event);
				} catch (Throwable e) {
					this.context.getLogger().warn(e.getMessage(), e);
				} finally {
					this.context.fireContainerEvent("afterSessionCreated", listener);
				}
			});
			org.apache.catalina.Session result = this.getSession(session, batch);
			close = false;
			return result;
		} catch (RuntimeException | Error e) {
			batch.discard();
			throw e;
		} finally {
			if (close) {
				batch.close();
			}
		}
	}

	@Override
	public org.apache.catalina.Session findSession(String sessionId) throws IOException {
		String id = parseSessionId(sessionId);
		boolean close = true;
		// Batch will be closed by Session.close();
		Batch batch = this.manager.getBatchFactory().get();
		try {
			Session session = this.manager.findSession(id);
			if (session == null) {
				return null;
			}
			org.apache.catalina.Session result = this.getSession(session, batch);
			close = false;
			return result;
		} catch (RuntimeException | Error e) {
			batch.discard();
			throw e;
		} finally {
			if (close) {
				batch.close();
			}
		}
	}

	@Override
	public void changeSessionId(org.apache.catalina.Session session, String id) {
		session.tellChangedSessionId(id, session.getId(), true, true);
	}

	@Override
	public Context getContext() {
		return this.context;
	}

	@Override
	public boolean willAttributeDistribute(String name, Object value) {
		return this.marshallability.isMarshallable(value);
	}

	@Override
	public boolean getNotifyAttributeListenerOnUnchangedValue() {
		return false;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy