001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime; 020 021import java.util.Collections; 022import java.util.Iterator; 023import java.util.Map; 024import java.util.Map.Entry; 025 026import lucee.commons.collection.LongKeyList; 027import lucee.commons.lang.SizeOf; 028import lucee.commons.lang.SystemOut; 029import lucee.runtime.config.ConfigImpl; 030import lucee.runtime.dump.DumpData; 031import lucee.runtime.dump.DumpProperties; 032import lucee.runtime.dump.DumpTable; 033import lucee.runtime.dump.DumpUtil; 034import lucee.runtime.dump.Dumpable; 035import lucee.runtime.dump.SimpleDumpData; 036import lucee.runtime.type.Sizeable; 037import lucee.runtime.type.dt.DateTimeImpl; 038import lucee.runtime.type.util.ArrayUtil; 039 040import org.apache.commons.collections.map.ReferenceMap; 041 042/** 043 * pool to handle pages 044 */ 045public final class PageSourcePool implements Dumpable,Sizeable { 046 047 private Map<Object,PageSource> pageSources=Collections.synchronizedMap(new ReferenceMap(ReferenceMap.SOFT, ReferenceMap.SOFT)); 048 //timeout timeout for files 049 private long timeout; 050 //max size of the pool cache 051 private int maxSize; 052 053 /** 054 * constructor of the class 055 */ 056 public PageSourcePool() { 057 this.timeout=10000; 058 this.maxSize=1000; 059 } 060 061 /** 062 * return pages matching to key 063 * @param key key for the page 064 * @param updateAccesTime define if do update access time 065 * @return page 066 */ 067 public PageSource getPageSource(Object key,boolean updateAccesTime) {// this method is used from Morpheus 068 Object o=pageSources.get(key); 069 if(o==null) return null; 070 071 PageSource ps=(PageSource) o; 072 if(updateAccesTime)ps.setLastAccessTime(); 073 return ps; 074 } 075 076 077 /** 078 * sts a page object to the page pool 079 * @param key key reference to store page object 080 * @param ps pagesource to store 081 */ 082 public void setPage(Object key, PageSource ps) { 083 ps.setLastAccessTime(); 084 pageSources.put(key,ps); 085 } 086 087 /** 088 * returns if page object exists 089 * @param key key reference to a page object 090 * @return has page object or not 091 */ 092 public boolean exists(Object key) { 093 return pageSources.containsKey(key); 094 } 095 096 /** 097 * @return returns a array of all keys in the page pool 098 */ 099 public Object[] keys() { 100 return ArrayUtil.keys(pageSources); 101 } 102 103 /** 104 * removes a page from the page pool 105 * @param key key reference to page object 106 * @return page object matching to key reference 107 */ 108 public boolean remove(Object key) { 109 return pageSources.remove(key)!=null; 110 } 111 112 /** 113 * @return returns the size of the pool 114 */ 115 public int size() { 116 return pageSources.size(); 117 } 118 119 /** 120 * @return returns if pool is empty or not 121 */ 122 public boolean isEmpty() { 123 return pageSources.isEmpty(); 124 } 125 126 /** 127 * clear unused pages from page pool 128 */ 129 public void clearUnused(ConfigImpl config) { 130 131 SystemOut.printDate(config.getOutWriter(),"PagePool: "+size()+">("+maxSize+")"); 132 if(size()>maxSize) { 133 Object[] keys=keys(); 134 LongKeyList list=new LongKeyList(); 135 for(int i=0;i<keys.length;i++) { 136 PageSource ps= getPageSource(keys[i],false); 137 long updateTime=ps.getLastAccessTime(); 138 if(updateTime+timeout<System.currentTimeMillis()) { 139 long add=((ps.getAccessCount()-1)*10000); 140 if(add>timeout)add=timeout; 141 list.add(updateTime+add,keys[i]); 142 } 143 } 144 while(size()>maxSize) { 145 Object key = list.shift(); 146 if(key==null)break; 147 remove(key); 148 } 149 } 150 } 151 152 @Override 153 public DumpData toDumpData(PageContext pageContext,int maxlevel, DumpProperties dp) { 154 maxlevel--; 155 Iterator<Object> it = pageSources.keySet().iterator(); 156 157 158 DumpTable table = new DumpTable("#FFCC00","#FFFF00","#000000"); 159 table.setTitle("Page Source Pool"); 160 table.appendRow(1,new SimpleDumpData("Count"),new SimpleDumpData(pageSources.size())); 161 while(it.hasNext()) { 162 PageSource ps= pageSources.get(it.next()); 163 DumpTable inner = new DumpTable("#FFCC00","#FFFF00","#000000"); 164 inner.setWidth("100%"); 165 inner.appendRow(1,new SimpleDumpData("source"),new SimpleDumpData(ps.getDisplayPath())); 166 inner.appendRow(1,new SimpleDumpData("last access"),DumpUtil.toDumpData(new DateTimeImpl(pageContext,ps.getLastAccessTime(),false), pageContext,maxlevel,dp)); 167 inner.appendRow(1,new SimpleDumpData("access count"),new SimpleDumpData(ps.getAccessCount())); 168 table.appendRow(1,new SimpleDumpData("Sources"),inner); 169 } 170 return table; 171 } 172 173 /** 174 * remove all Page from Pool using this classloader 175 * @param cl 176 */ 177 public void clearPages(ClassLoader cl) { 178 synchronized(pageSources){ 179 Iterator<Entry<Object, PageSource>> it = this.pageSources.entrySet().iterator(); 180 PageSourceImpl entry; 181 while(it.hasNext()) { 182 entry = (PageSourceImpl) it.next().getValue(); 183 if(cl!=null)entry.clear(cl); 184 else entry.clear(); 185 } 186 } 187 } 188 189 public void clear() { 190 pageSources.clear(); 191 } 192 public int getMaxSize() { 193 return maxSize; 194 } 195 196 @Override 197 public long sizeOf() { 198 return SizeOf.size(this.timeout) 199 +SizeOf.size(this.maxSize) 200 +SizeOf.size(this.pageSources); 201 } 202}