001 package railo.runtime; 002 003 import java.util.Collections; 004 import java.util.Iterator; 005 import java.util.Map; 006 import java.util.Map.Entry; 007 008 import org.apache.commons.collections.map.ReferenceMap; 009 010 import railo.commons.collections.LongKeyList; 011 import railo.commons.lang.SizeOf; 012 import railo.commons.lang.SystemOut; 013 import railo.runtime.config.ConfigImpl; 014 import railo.runtime.dump.DumpData; 015 import railo.runtime.dump.DumpProperties; 016 import railo.runtime.dump.DumpTable; 017 import railo.runtime.dump.DumpUtil; 018 import railo.runtime.dump.Dumpable; 019 import railo.runtime.dump.SimpleDumpData; 020 import railo.runtime.type.Sizeable; 021 import railo.runtime.type.dt.DateTimeImpl; 022 import railo.runtime.type.util.ArrayUtil; 023 024 /** 025 * pool to handle pages 026 */ 027 public final class PageSourcePool implements Dumpable,Sizeable { 028 029 private Map<Object,PageSource> pageSources=Collections.synchronizedMap(new ReferenceMap(ReferenceMap.SOFT, ReferenceMap.SOFT)); 030 //timeout timeout for files 031 private long timeout; 032 //max size of the pool cache 033 private int maxSize; 034 035 /** 036 * constructor of the class 037 */ 038 public PageSourcePool() { 039 this.timeout=10000; 040 this.maxSize=1000; 041 } 042 043 /** 044 * return pages matching to key 045 * @param key key for the page 046 * @param updateAccesTime define if do update access time 047 * @return page 048 */ 049 public PageSource getPageSource(Object key,boolean updateAccesTime) {// this method is used from Morpheus 050 Object o=pageSources.get(key); 051 if(o==null) return null; 052 053 PageSource ps=(PageSource) o; 054 if(updateAccesTime)ps.setLastAccessTime(); 055 return ps; 056 } 057 058 059 /** 060 * sts a page object to the page pool 061 * @param key key reference to store page object 062 * @param ps pagesource to store 063 */ 064 public void setPage(Object key, PageSource ps) { 065 ps.setLastAccessTime(); 066 pageSources.put(key,ps); 067 } 068 069 /** 070 * returns if page object exists 071 * @param key key reference to a page object 072 * @return has page object or not 073 */ 074 public boolean exists(Object key) { 075 return pageSources.containsKey(key); 076 } 077 078 /** 079 * @return returns a array of all keys in the page pool 080 */ 081 public Object[] keys() { 082 return ArrayUtil.keys(pageSources); 083 } 084 085 /** 086 * removes a page from the page pool 087 * @param key key reference to page object 088 * @return page object matching to key reference 089 */ 090 public boolean remove(Object key) { 091 return pageSources.remove(key)!=null; 092 } 093 094 /** 095 * @return returns the size of the pool 096 */ 097 public int size() { 098 return pageSources.size(); 099 } 100 101 /** 102 * @return returns if pool is empty or not 103 */ 104 public boolean isEmpty() { 105 return pageSources.isEmpty(); 106 } 107 108 /** 109 * clear unused pages from page pool 110 */ 111 public void clearUnused(ConfigImpl config) { 112 113 SystemOut.printDate(config.getOutWriter(),"PagePool: "+size()+">("+maxSize+")"); 114 if(size()>maxSize) { 115 Object[] keys=keys(); 116 LongKeyList list=new LongKeyList(); 117 for(int i=0;i<keys.length;i++) { 118 PageSource ps= getPageSource(keys[i],false); 119 long updateTime=ps.getLastAccessTime(); 120 if(updateTime+timeout<System.currentTimeMillis()) { 121 long add=((ps.getAccessCount()-1)*10000); 122 if(add>timeout)add=timeout; 123 list.add(updateTime+add,keys[i]); 124 } 125 } 126 while(size()>maxSize) { 127 Object key = list.shift(); 128 if(key==null)break; 129 remove(key); 130 } 131 } 132 } 133 134 @Override 135 public DumpData toDumpData(PageContext pageContext,int maxlevel, DumpProperties dp) { 136 maxlevel--; 137 Iterator<Object> it = pageSources.keySet().iterator(); 138 139 140 DumpTable table = new DumpTable("#FFCC00","#FFFF00","#000000"); 141 table.setTitle("Page Source Pool"); 142 table.appendRow(1,new SimpleDumpData("Count"),new SimpleDumpData(pageSources.size())); 143 while(it.hasNext()) { 144 PageSource ps= pageSources.get(it.next()); 145 DumpTable inner = new DumpTable("#FFCC00","#FFFF00","#000000"); 146 inner.setWidth("100%"); 147 inner.appendRow(1,new SimpleDumpData("source"),new SimpleDumpData(ps.getDisplayPath())); 148 inner.appendRow(1,new SimpleDumpData("last access"),DumpUtil.toDumpData(new DateTimeImpl(pageContext,ps.getLastAccessTime(),false), pageContext,maxlevel,dp)); 149 inner.appendRow(1,new SimpleDumpData("access count"),new SimpleDumpData(ps.getAccessCount())); 150 table.appendRow(1,new SimpleDumpData("Sources"),inner); 151 } 152 return table; 153 } 154 155 /** 156 * remove all Page from Pool using this classloader 157 * @param cl 158 */ 159 public void clearPages(ClassLoader cl) { 160 synchronized(pageSources){ 161 Iterator<Entry<Object, PageSource>> it = this.pageSources.entrySet().iterator(); 162 PageSourceImpl entry; 163 while(it.hasNext()) { 164 entry = (PageSourceImpl) it.next().getValue(); 165 if(cl!=null)entry.clear(cl); 166 else entry.clear(); 167 } 168 } 169 } 170 171 public void clear() { 172 pageSources.clear(); 173 } 174 public int getMaxSize() { 175 return maxSize; 176 } 177 178 @Override 179 public long sizeOf() { 180 return SizeOf.size(this.timeout) 181 +SizeOf.size(this.maxSize) 182 +SizeOf.size(this.pageSources); 183 } 184 }