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    }