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

com.jfinal.plugin.ehcache.CacheInterceptor Maven / Gradle / Ivy

Go to download

JFinal is a simple, light, rapid,independent, extensible Java WEB + ORM framework. The feature of JFinal looks like ruby on rails especially ActiveRecord.

There is a newer version: 5.2.3
Show newest version
/**
 * Copyright (c) 2011-2023, James Zhan 詹波 ([email protected]).
 *
 * 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.jfinal.plugin.ehcache;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.servlet.http.HttpServletRequest;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.render.Render;

/**
 * CacheInterceptor.
 */
public class CacheInterceptor implements Interceptor {
	
	private static final String renderKey = "_renderKey";
	private static ConcurrentHashMap lockMap = new ConcurrentHashMap(512);
	
	private ReentrantLock getLock(String key) {
		ReentrantLock lock = lockMap.get(key);
		if (lock != null) {
			return lock;
		}
		
		lock = new ReentrantLock();
		ReentrantLock previousLock = lockMap.putIfAbsent(key, lock);
		return previousLock == null ? lock : previousLock;
	}
	
	final public void intercept(Invocation inv) {
		Controller controller = inv.getController();
		String cacheName = buildCacheName(inv, controller);
		String cacheKey = buildCacheKey(inv, controller);
		Map cacheData = CacheKit.get(cacheName, cacheKey);
		if (cacheData == null) {
			Lock lock = getLock(cacheName);
			lock.lock();					// prevent cache snowslide
			try {
				cacheData = CacheKit.get(cacheName, cacheKey);
				if (cacheData == null) {
					inv.invoke();
					cacheAction(cacheName, cacheKey, controller);
					return ;
				}
			}
			finally {
				lock.unlock();
			}
		}
		
		useCacheDataAndRender(cacheData, controller);
	}
	
	// TODO 考虑与 EvictInterceptor 一样强制使用  @CacheName
	protected String buildCacheName(Invocation inv, Controller controller) {
		CacheName cacheName = inv.getMethod().getAnnotation(CacheName.class);
		if (cacheName != null)
			return cacheName.value();
		cacheName = controller.getClass().getAnnotation(CacheName.class);
		return (cacheName != null) ? cacheName.value() : inv.getActionKey();
	}
	
	protected String buildCacheKey(Invocation inv, Controller controller) {
		StringBuilder sb = new StringBuilder(inv.getActionKey());
		String urlPara = controller.getPara();
		if (urlPara != null)
			sb.append('/').append(urlPara);
		
		String queryString = controller.getRequest().getQueryString();
		if (queryString != null)
			sb.append('?').append(queryString);
		return sb.toString();
	}
	
	/**
	 * 通过继承 CacheInterceptor 并覆盖此方法支持更多类型的 Render
	 */
	protected RenderInfo createRenderInfo(Render render) {
		return new RenderInfo(render);
	}
	
	protected void cacheAction(String cacheName, String cacheKey, Controller controller) {
		HttpServletRequest request = controller.getRequest();
		Map cacheData = new HashMap();
		for (Enumeration names=request.getAttributeNames(); names.hasMoreElements();) {
			String name = names.nextElement();
			cacheData.put(name, request.getAttribute(name));
		}
		
		Render render = controller.getRender();
		if (render != null) {
			cacheData.put(renderKey, createRenderInfo(render));		// cache RenderInfo
		}
		CacheKit.put(cacheName, cacheKey, cacheData);
	}
	
	protected void useCacheDataAndRender(Map cacheData, Controller controller) {
		HttpServletRequest request = controller.getRequest();
		Set> set = cacheData.entrySet();
		for (Iterator> it=set.iterator(); it.hasNext();) {
			Entry entry = it.next();
			request.setAttribute(entry.getKey(), entry.getValue());
		}
		request.removeAttribute(renderKey);
		
		RenderInfo renderInfo = (RenderInfo)cacheData.get(renderKey);
		if (renderInfo != null) {
			controller.render(renderInfo.createRender());		// set render from cacheData
		}
	}
}









© 2015 - 2025 Weber Informatics LLC | Privacy Policy