QuerydslHttpRequestContextHolder.java

/*******************************************************************************
 * Copyright (c) 2018 @gt_tech
 *
 * 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 org.bitbucket.gt_tech.spring.data.querydsl.value.operators.experimental;

import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Constructor;

/**
 * Provides access to users of this component to persist, retrieve, unset
 * {@link QuerydslHttpRequestContext}. It delegates to a specific
 * {@link QuerydslHttpRequestContextHolderStrategy} based on runtime
 * configurations. Default strategy used is
 * {@link QuerydslHttpRequestContextHolder#MODE_THREADLOCAL} which can be used
 * by configuring JVM property -
 * {@link QuerydslHttpRequestContextHolder#SYSTEM_PROPERTY}.
 * 
 * The property can contain either of
 * {@link QuerydslHttpRequestContextHolder#MODE_THREADLOCAL} or
 * {@link QuerydslHttpRequestContextHolder#MODE_INHERITABLETHREADLOCAL} but if
 * it contains any other value, it is assumed to be a cannonical classname for
 * strategy to be used by this holder.
 * 
 * 
 * @author gt_tech
 *
 */
public final class QuerydslHttpRequestContextHolder {

	/**
	 * {@link ThreadLocal} based QuerydslHttpRequestContextHolderStrategy to be
	 * used.
	 */
	public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL";
	/**
	 * {@link InheritableThreadLocal} based
	 * QuerydslHttpRequestContextHolderStrategy to be used.
	 */
	public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL";
	/**
	 * System property to configure/override the
	 * QuerydslHttpRequestContextHolderStrategy to be used.
	 * 
	 * <p>
	 * The property can contain either of
	 * {@link QuerydslHttpRequestContextHolder#MODE_THREADLOCAL} or
	 * {@link QuerydslHttpRequestContextHolder#MODE_INHERITABLETHREADLOCAL} but
	 * if it contains any other value, it is assumed to be a cannonical
	 * classname for strategy to be used by this holder.
	 * </p>
	 */
	public static final String SYSTEM_PROPERTY = "querydsl.experimental.operator.web.context.strategy";
	private static String strategyName = System.getProperty(SYSTEM_PROPERTY);
	private static QuerydslHttpRequestContextHolderStrategy strategy;

	static {
		initialize();
	}

	// ~ Methods
	// ========================================================================================================

	/**
	 * Explicitly clears the context value from the current thread.
	 */
	public static void clearContext() {
		strategy.clearContext();
	}

	/**
	 * Obtain the current <code>QuerydslHttpRequestContext</code>.
	 *
	 * @return the context if available, <code>null</code> otherwise
	 */
	public static QuerydslHttpRequestContext getContext() {
		return strategy.getContext();
	}

	private static void initialize() {
		if (!StringUtils.hasText(strategyName)) {
			// Set default
			strategyName = MODE_THREADLOCAL;
		}

		if (strategyName.equals(MODE_THREADLOCAL)) {
			strategy = new ThreadLocalQuerydslHttpRequestContextHolderStrategy(false);
		} else if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) {
			strategy = new ThreadLocalQuerydslHttpRequestContextHolderStrategy(true);
		} else {
			// Try to load a custom strategy
			try {
				Class<?> clazz = Class.forName(strategyName);
				Constructor<?> customStrategy = clazz.getConstructor();
				strategy = (QuerydslHttpRequestContextHolderStrategy) customStrategy.newInstance();
			} catch (Exception ex) {
				ReflectionUtils.handleReflectionException(ex);
			}
		}
	}

	/**
	 * Associates a new <code>QuerydslHttpRequestContext</code> with the holder
	 * strategy
	 *
	 * @param context
	 *            the new <code>QuerydslHttpRequestContext</code> (may not be
	 *            <code>null</code>)
	 */
	public static void setContext(QuerydslHttpRequestContext context) {
		strategy.setContext(context);
	}

	/**
	 * Changes the preferred strategy. Do <em>NOT</em> call this method more
	 * than once for a given JVM, as it will re-initialize the strategy and
	 * adversely affect any existing threads using the old strategy.
	 *
	 * @param strategyName
	 *            the fully qualified class name of the strategy that should be
	 *            used.
	 */
	public static void setStrategyName(String strategyName) {
		QuerydslHttpRequestContextHolder.strategyName = strategyName;
		initialize();
	}

	/**
	 * Allows retrieval of the context strategy.
	 *
	 * @return the configured strategy for storing the security context.
	 */
	public static QuerydslHttpRequestContextHolderStrategy getContextHolderStrategy() {
		return strategy;
	}
}