package railo.runtime; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.collections.map.ReferenceMap; import railo.commons.collection.LongKeyList; import railo.commons.lang.SizeOf; import railo.commons.lang.SystemOut; import railo.runtime.config.ConfigImpl; import railo.runtime.dump.DumpData; import railo.runtime.dump.DumpProperties; import railo.runtime.dump.DumpTable; import railo.runtime.dump.DumpUtil; import railo.runtime.dump.Dumpable; import railo.runtime.dump.SimpleDumpData; import railo.runtime.type.Sizeable; import railo.runtime.type.dt.DateTimeImpl; import railo.runtime.type.util.ArrayUtil; /** * pool to handle pages */ public final class PageSourcePool implements Dumpable,Sizeable { private Map<Object,PageSource> pageSources=Collections.synchronizedMap(new ReferenceMap(ReferenceMap.SOFT, ReferenceMap.SOFT)); //timeout timeout for files private long timeout; //max size of the pool cache private int maxSize; /** * constructor of the class */ public PageSourcePool() { this.timeout=10000; this.maxSize=1000; } /** * return pages matching to key * @param key key for the page * @param updateAccesTime define if do update access time * @return page */ public PageSource getPageSource(Object key,boolean updateAccesTime) {// this method is used from Morpheus Object o=pageSources.get(key); if(o==null) return null; PageSource ps=(PageSource) o; if(updateAccesTime)ps.setLastAccessTime(); return ps; } /** * sts a page object to the page pool * @param key key reference to store page object * @param ps pagesource to store */ public void setPage(Object key, PageSource ps) { ps.setLastAccessTime(); pageSources.put(key,ps); } /** * returns if page object exists * @param key key reference to a page object * @return has page object or not */ public boolean exists(Object key) { return pageSources.containsKey(key); } /** * @return returns a array of all keys in the page pool */ public Object[] keys() { return ArrayUtil.keys(pageSources); } /** * removes a page from the page pool * @param key key reference to page object * @return page object matching to key reference */ public boolean remove(Object key) { return pageSources.remove(key)!=null; } /** * @return returns the size of the pool */ public int size() { return pageSources.size(); } /** * @return returns if pool is empty or not */ public boolean isEmpty() { return pageSources.isEmpty(); } /** * clear unused pages from page pool */ public void clearUnused(ConfigImpl config) { SystemOut.printDate(config.getOutWriter(),"PagePool: "+size()+">("+maxSize+")"); if(size()>maxSize) { Object[] keys=keys(); LongKeyList list=new LongKeyList(); for(int i=0;i<keys.length;i++) { PageSource ps= getPageSource(keys[i],false); long updateTime=ps.getLastAccessTime(); if(updateTime+timeout<System.currentTimeMillis()) { long add=((ps.getAccessCount()-1)*10000); if(add>timeout)add=timeout; list.add(updateTime+add,keys[i]); } } while(size()>maxSize) { Object key = list.shift(); if(key==null)break; remove(key); } } } @Override public DumpData toDumpData(PageContext pageContext,int maxlevel, DumpProperties dp) { maxlevel--; Iterator<Object> it = pageSources.keySet().iterator(); DumpTable table = new DumpTable("#FFCC00","#FFFF00","#000000"); table.setTitle("Page Source Pool"); table.appendRow(1,new SimpleDumpData("Count"),new SimpleDumpData(pageSources.size())); while(it.hasNext()) { PageSource ps= pageSources.get(it.next()); DumpTable inner = new DumpTable("#FFCC00","#FFFF00","#000000"); inner.setWidth("100%"); inner.appendRow(1,new SimpleDumpData("source"),new SimpleDumpData(ps.getDisplayPath())); inner.appendRow(1,new SimpleDumpData("last access"),DumpUtil.toDumpData(new DateTimeImpl(pageContext,ps.getLastAccessTime(),false), pageContext,maxlevel,dp)); inner.appendRow(1,new SimpleDumpData("access count"),new SimpleDumpData(ps.getAccessCount())); table.appendRow(1,new SimpleDumpData("Sources"),inner); } return table; } /** * remove all Page from Pool using this classloader * @param cl */ public void clearPages(ClassLoader cl) { synchronized(pageSources){ Iterator<Entry<Object, PageSource>> it = this.pageSources.entrySet().iterator(); PageSourceImpl entry; while(it.hasNext()) { entry = (PageSourceImpl) it.next().getValue(); if(cl!=null)entry.clear(cl); else entry.clear(); } } } public void clear() { pageSources.clear(); } public int getMaxSize() { return maxSize; } @Override public long sizeOf() { return SizeOf.size(this.timeout) +SizeOf.size(this.maxSize) +SizeOf.size(this.pageSources); } }