<commit_before>/*-
 *  Copyright 2015 Crimson Hexagon
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.crimsonhexagon.rsm;

import java.io.IOException;
import java.util.Enumeration;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.Session;
import org.apache.catalina.connector.Request;
import org.apache.catalina.session.ManagerBase;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;

/**
 * Manages {@link RedisSession}s
 * 
 * @author <NAME>
 */
public abstract class RedisSessionManager extends ManagerBase {
	protected final Log log = LogFactory.getLog(this.getClass());

	/**
	 * Default value to prefix redis keys with.
	 */
	public static final String DEFAULT_SESSION_KEY_PREFIX="_rsm_";
	
	private int sessionExpirationTime; // in minutes
	private RedisSessionClient client;
	private String sessionKeyPrefix = DEFAULT_SESSION_KEY_PREFIX;
	private String ignorePattern = RedisSessionRequestValve.DEFAULT_IGNORE_PATTERN;
	private boolean saveOnChange;
	private boolean forceSaveAfterRequest;
	private boolean dirtyOnMutation;
	
	private ThreadLocal<RedisSessionState> currentSessionState = InheritableThreadLocal.withInitial(RedisSessionState::new);
	
	private RedisSessionRequestValve requestValve;

	/**
	 * Construct the {@link RedisSessionClient}
	 * @return
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	protected abstract RedisSessionClient buildClient() throws ClassNotFoundException, InstantiationException, IllegalAccessException;
	
	/**
	 * Should the {@link RedisSession} be saved immediately when an attribute changes
	 * @return
	 */
	public boolean isSaveOnChange() {
		return saveOnChange;
	}

	/**
	 * Should the {@link RedisSession} be saved on completion of every request regardless of {@link RedisSession#isDirty()}
	 * @return
	 */
	public boolean isForceSaveAfterRequest() {
		return forceSaveAfterRequest;
	}
	
	/**
	 * Should any attribute mutation result in marking the session as dirty
	 * @return
	 */
	public boolean isDirtyOnMutation() {
		return dirtyOnMutation;
	}

	/**
	 * Obtain the {@link ClassLoader} for this context. Necessary for deserialization of {@link RedisSession}s
	 * @return
	 */
	public ClassLoader getContainerClassLoader() {
		return getContext().getLoader().getClassLoader();
	}
	
	@Override
	public void load() throws ClassNotFoundException, IOException {
		// noop
	}

	@Override
	public void unload() throws IOException {
		// noop
	}

	@Override
	protected synchronized void startInternal() throws LifecycleException {
		super.startInternal();

		try {
			this.client = buildClient();
		} catch (Throwable t) {
			log.fatal("Unable to load serializer", t);
			throw new LifecycleException(t);
		}

		this.requestValve = new RedisSessionRequestValve(this, ignorePattern);
		getContext().getParent().getPipeline().addValve(requestValve);
        this.sessionExpirationTime = getContext().getSessionTimeout();
        if (this.sessionExpirationTime < 0) {
        	log.warn("Ignoring negative session expiration time");
        	this.sessionExpirationTime = 0;
        }
		log.info("Will expire sessions after " + sessionExpirationTime + " minutes");
		setDistributable(true);
		setState(LifecycleState.STARTING);
	}<commit_msg>deprecation cleanup<commit_after>/*-
 *  Copyright 2015 <NAME>
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.crimsonhexagon.rsm;

import java.io.IOException;
import java.util.Enumeration;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.Session;
import org.apache.catalina.connector.Request;
import org.apache.catalina.session.ManagerBase;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;

/**
 * Manages {@link RedisSession}s
 * 
 * @author <NAME>
 */
public abstract class RedisSessionManager extends ManagerBase {
	protected final Log log = LogFactory.getLog(this.getClass());

	/**
	 * Default value to prefix redis keys with.
	 */
	public static final String DEFAULT_SESSION_KEY_PREFIX="_rsm_";
	
	private int sessionExpirationTime; // in minutes
	private RedisSessionClient client;
	private String sessionKeyPrefix = DEFAULT_SESSION_KEY_PREFIX;
	private String ignorePattern = RedisSessionRequestValve.DEFAULT_IGNORE_PATTERN;
	private boolean saveOnChange;
	private boolean forceSaveAfterRequest;
	private boolean dirtyOnMutation;
	
	private ThreadLocal<RedisSessionState> currentSessionState = InheritableThreadLocal.withInitial(RedisSessionState::new);
	
	private RedisSessionRequestValve requestValve;

	/**
	 * Construct the {@link RedisSessionClient}
	 * @return
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	protected abstract RedisSessionClient buildClient() throws ClassNotFoundException, InstantiationException, IllegalAccessException;
	
	/**
	 * Should the {@link RedisSession} be saved immediately when an attribute changes
	 * @return
	 */
	public boolean isSaveOnChange() {
		return saveOnChange;
	}

	/**
	 * Should the {@link RedisSession} be saved on completion of every request regardless of {@link RedisSession#isDirty()}
	 * @return
	 */
	public boolean isForceSaveAfterRequest() {
		return forceSaveAfterRequest;
	}
	
	/**
	 * Should any attribute mutation result in marking the session as dirty
	 * @return
	 */
	public boolean isDirtyOnMutation() {
		return dirtyOnMutation;
	}

	/**
	 * Obtain the {@link ClassLoader} for this context. Necessary for deserialization of {@link RedisSession}s
	 * @return
	 */
	public ClassLoader getContainerClassLoader() {
		return getContext().getLoader().getClassLoader();
	}
	
	@Override
	public void load() throws ClassNotFoundException, IOException {
		// noop
	}

	@Override
	public void unload() throws IOException {
		// noop
	}

	@Override
	protected synchronized void startInternal() throws LifecycleException {
		super.startInternal();

		try {
			this.client = buildClient();
		} catch (Throwable t) {
			log.fatal("Unable to load serializer", t);
			throw new LifecycleException(t);
		}

		this.requestValve = new RedisSessionRequestValve(this, ignorePattern);
		getContext().getParent().getPipeline().addValve(requestValve);
        this.sessionExpirationTime = getContext().getSessionTimeout();
        if (this.sessionExpirationTime < 0) {
        	log.warn("Ignoring negative session expiration time");
        	this.sessionExpirationTime = 0;
        }
		log.info("Will expire sessions after " + sessionExpirationTime + " minutes");
		setState(LifecycleState.STARTING);
	}
{'fraction_non_alphanumeric': 0.08977777777777778, 'fraction_numerical': 0.0025396825396825397, 'mean_word_length': 4.562146892655368, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5525957', 'n_tokens_mistral': 2290, 'n_tokens_neox': 2126, 'n_words': 643}