/** * * Copyright 2014 The Darks ORM Project (Liu lihua) * * 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 darks.orm.core.cache.scope; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.servlet.http.HttpSession; import net.sf.ehcache.CacheException; import darks.orm.core.cache.CacheContext.CacheKeyType; import darks.orm.core.cache.CacheController; import darks.orm.core.cache.CacheKey; import darks.orm.core.cache.CacheList; import darks.orm.core.cache.CacheObject; import darks.orm.core.cache.control.CacheControllerFactroy; import darks.orm.core.cache.strategy.CopyStrategy; import darks.orm.core.config.CacheConfiguration; import darks.orm.core.config.Configuration; import darks.orm.core.data.EntityData; import darks.orm.core.data.FieldData; import darks.orm.core.data.xml.CacheConfigData; import darks.orm.core.session.SessionContext; import darks.orm.log.Logger; import darks.orm.log.LoggerFactory; import darks.orm.util.ByteHelper; import darks.orm.web.context.RequestContext; @SuppressWarnings("unchecked") public class SessionCacheFactory implements CacheFactory { private static final Logger logger = LoggerFactory.getLogger(SessionCacheFactory.class); private static final String SESSION_KEYLIST_KEY = "DARKS$SESSION$KEYLIST_KEY"; private static final String SESSION_ENTITYMAP_KEY = "DARKS$SESSION$ENTITYMAP_KEY"; private static final String SESSION_ENTITYLISTMAP_KEY = "DARKS$SESSION$ENTITYLISTMAP_KEY"; private static final String SESSION_CONTROLLER_KEY = "DARKS$SESSION$CONTROLLER_KEY"; private static volatile SessionCacheFactory instace = null; private static final ReadWriteLock rwlock = new ReentrantReadWriteLock(); private static final Lock rlock = rwlock.readLock(); private static final Lock wlock = rwlock.writeLock(); private CacheConfigData sessionConfigData; private CopyStrategy copyStrategy; private SessionCacheFactory() { try { Configuration cfg = SessionContext.getConfigure(); CacheConfiguration cacheCfg = cfg.getCacheConfig(); if (cacheCfg == null) return; sessionConfigData = cacheCfg.getSessionCacheData(); if (sessionConfigData == null) return; copyStrategy = sessionConfigData.getCopyStrategy(); } catch (Exception e) { e.printStackTrace(); } } public static CacheFactory getInstance() { Configuration cfg = SessionContext.getConfigure(); if (cfg == null) return null; CacheConfiguration cacheCfg = cfg.getCacheConfig(); if (cacheCfg == null) return null; CacheConfigData data = cacheCfg.getThreadCacheData(); if (data == null) return null; if (instace == null) { instace = new SessionCacheFactory(); } return instace; } /** * ������� * * @param key ����KEY * @param obj ����ʵ�� * @throws Exception */ public void cacheObject(CacheKey key, Object obj) throws Exception { if (key == null || obj == null) return; EntityData data = key.getData(); if (data == null || !ByteHelper.isSerializable(data)) return; Map<CacheKey, CacheList> listMap = getListMap(); CacheController controller = getCacheController(); wlock.lock(); try { if (obj instanceof List && !sessionConfigData.isEntirety()) { List list = (List)obj; if (list.size() > sessionConfigData.getMaxObject()) { throw new CacheException("the size of list cacheing is flowover the max limit"); } FieldData pkfdata = data.getPkField(); Map<CacheKey, Object> map = new ConcurrentHashMap<CacheKey, Object>(); List<CacheKey> clist = new ArrayList<CacheKey>(); for (Object ob : list) { int piId = (Integer)pkfdata.getValue(ob); CacheKey newkey = new CacheKey(data, piId, CacheKeyType.SingleKey); Object value = new CacheObject(copyStrategy, newkey, ob);// new // SoftReference<Object>(ob);//(Object)ByteHelper.ObjectToByte(ob); controller.cacheObject(newkey, value); map.put(newkey, value); clist.add(newkey); } CacheList cacheList = new CacheList(map, clist); listMap.put(key, cacheList); } else { Object value = new CacheObject(copyStrategy, key, obj);// new // SoftReference<Object>(obj);//(Object)ByteHelper.ObjectToByte(obj); controller.cacheObject(key, value); } } catch (Exception e) { throw new CacheException(e.getMessage(), e); } finally { wlock.unlock(); } } /** * ��ö��� * * @param key ����KEY * @return ����ʵ�� * @throws Exception */ public Object getObject(CacheKey key) throws Exception { if (key.getData() == null) return false; if (!key.getData().isSerializable()) return false; Map<CacheKey, CacheList> listMap = getListMap(); CacheController controller = getCacheController(); rlock.lock(); try { if ((key.getCacheKeyType() == CacheKeyType.ListKey || key.getCacheKeyType() == CacheKeyType.PageKey) && !sessionConfigData.isEntirety()) { CacheList cacheList = listMap.get(key); if (cacheList == null) return null; key.setCount(cacheList.getCount()); List<CacheKey> clist = cacheList.getList(); List<Object> list = new ArrayList<Object>(clist.size()); for (CacheKey ckey : clist) { CacheObject val = (CacheObject)controller.getObject(ckey); if (val == null) return null; val.setLastIdleTime(System.currentTimeMillis()); list.add(val.getObject()); } return list; } CacheObject value = (CacheObject)controller.getObject(key); if (value == null) return null; key.setCount(value.getKey().getCount()); value.setLastIdleTime(System.currentTimeMillis()); return value.getObject(); } catch (Exception e) { throw e; } finally { rlock.unlock(); } } /** * �������Ƿ����ӵ�д˻���KEY�Ķ��� * * @param key ����KEY * @return true���� false������ */ public boolean containKey(CacheKey key) { Map<CacheKey, Object> entityMap = getEntityMap(); Map<CacheKey, CacheList> listMap = getListMap(); rlock.lock(); try { if ((key.getCacheKeyType() == CacheKeyType.ListKey || key.getCacheKeyType() == CacheKeyType.PageKey) && !sessionConfigData.isEntirety()) { return listMap.containsKey(key); } return entityMap.containsKey(key); } finally { rlock.unlock(); } } /** * ��ü�ֵ�б� * * @return ��ֵ���� */ private Queue<CacheKey> getKeysList() { HttpSession session = RequestContext.getInstance().getSession(); Queue<CacheKey> keysList = (Queue<CacheKey>)session.getAttribute(SESSION_KEYLIST_KEY); if (keysList == null) { keysList = new ConcurrentLinkedQueue<CacheKey>(); session.setAttribute(SESSION_KEYLIST_KEY, keysList); } return keysList; } /** * ���ʵ��MAP * * @return MAP */ private Map<CacheKey, Object> getEntityMap() { HttpSession session = RequestContext.getInstance().getSession(); Map<CacheKey, Object> entityMap = (Map<CacheKey, Object>)session.getAttribute(SESSION_ENTITYMAP_KEY); if (entityMap == null) { int initnum = 0; int max = sessionConfigData.getMaxObject(); if (max < 1000) { initnum = max * 2 / 3; } else if (max < 10000) { initnum = max * 1 / 5; } else if (max > 10000) { initnum = max * 1 / 100; } entityMap = new ConcurrentHashMap<CacheKey, Object>(initnum); session.setAttribute(SESSION_ENTITYMAP_KEY, entityMap); } return entityMap; } private Map<CacheKey, CacheList> getListMap() { HttpSession session = RequestContext.getInstance().getSession(); Map<CacheKey, CacheList> listMap = (Map<CacheKey, CacheList>)session.getAttribute(SESSION_ENTITYLISTMAP_KEY); if (listMap == null) { listMap = new ConcurrentHashMap<CacheKey, CacheList>(64); session.setAttribute(SESSION_ENTITYLISTMAP_KEY, listMap); } return listMap; } private CacheController getCacheController() { HttpSession session = RequestContext.getInstance().getSession(); CacheController ctrl = (CacheController)session.getAttribute(SESSION_CONTROLLER_KEY); if (ctrl == null) { Queue<CacheKey> keysList = getKeysList(); Map<CacheKey, Object> entityMap = getEntityMap(); Map<CacheKey, CacheList> listMap = getListMap(); ctrl = CacheControllerFactroy.getCacheController(sessionConfigData, keysList, entityMap, listMap); session.setAttribute(SESSION_CONTROLLER_KEY, ctrl); } return ctrl; } public void debug() { Queue<CacheKey> keysList = getKeysList(); Map<CacheKey, Object> entityMap = getEntityMap(); Map<CacheKey, CacheList> listMap = getListMap(); System.out.println(keysList.size() + " " + entityMap.size() + " " + listMap.size()); for (CacheKey key : keysList) { System.out.println(key.getId() + " " + key.getCacheKeyType()); } } public void flush() { Queue<CacheKey> keysList = getKeysList(); Map<CacheKey, Object> entityMap = getEntityMap(); Map<CacheKey, CacheList> listMap = getListMap(); wlock.lock(); try { listMap.clear(); keysList.clear(); entityMap.clear(); } catch (Exception e) { } finally { wlock.unlock(); } } }