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.functions.system;
020
021import java.util.Iterator;
022import java.util.Map;
023import java.util.Map.Entry;
024
025import javax.servlet.http.HttpServletRequest;
026
027import lucee.commons.io.SystemUtil;
028import lucee.commons.io.res.Resource;
029import lucee.commons.lang.SizeAndCount;
030import lucee.commons.lang.SizeAndCount.Size;
031import lucee.loader.engine.CFMLEngineFactory;
032import lucee.runtime.CFMLFactoryImpl;
033import lucee.runtime.Mapping;
034import lucee.runtime.MappingImpl;
035import lucee.runtime.PageContext;
036import lucee.runtime.PageContextImpl;
037import lucee.runtime.PageSourceImpl;
038import lucee.runtime.PageSourcePool;
039import lucee.runtime.config.ConfigServer;
040import lucee.runtime.config.ConfigWeb;
041import lucee.runtime.config.ConfigWebImpl;
042import lucee.runtime.config.ConfigWebUtil;
043import lucee.runtime.debug.ActiveLock;
044import lucee.runtime.debug.ActiveQuery;
045import lucee.runtime.engine.CFMLEngineImpl;
046import lucee.runtime.exp.PageException;
047import lucee.runtime.ext.function.Function;
048import lucee.runtime.lock.LockManager;
049import lucee.runtime.op.Caster;
050import lucee.runtime.type.Collection;
051import lucee.runtime.type.Collection.Key;
052import lucee.runtime.type.KeyImpl;
053import lucee.runtime.type.Query;
054import lucee.runtime.type.QueryImpl;
055import lucee.runtime.type.Struct;
056import lucee.runtime.type.StructImpl;
057import lucee.runtime.type.dt.DateTimeImpl;
058import lucee.runtime.type.scope.ScopeContext;
059import lucee.runtime.type.util.KeyConstants;
060
061public final class GetUsageData implements Function {
062    
063        private static final Key START_TIME = KeyImpl.init("starttime");
064        private static final Key CACHED_QUERIES = KeyImpl.init("cachedqueries");
065        private static final Key OPEN_CONNECTIONS = KeyImpl.init("openconnections");
066        private static final Key ELEMENTS = KeyImpl.init("elements");
067        private static final Key USERS = KeyImpl.init("users");
068        private static final Key QUERIES = KeyImpl.init("queries");
069        private static final Key LOCKS = KeyImpl.init("locks");
070        
071        public static Struct call(PageContext pc) throws PageException  {
072                ConfigWeb cw = pc.getConfig();
073                ConfigServer cs = cw.getConfigServer("server");
074                ConfigWeb[] webs = cs.getConfigWebs();
075                CFMLEngineFactory.getInstance();
076                CFMLEngineImpl engine = (CFMLEngineImpl) cs.getCFMLEngine();
077                
078                Struct sct=new StructImpl();
079                
080                
081                // Locks
082                /*LockManager manager = pc.getConfig().getLockManager();
083        String[] locks = manager.getOpenLockNames();
084        for(int i=0;i<locks.length;i++){
085                locks[i].
086        }
087        if(!ArrayUtil.isEmpty(locks)) 
088                strLocks=" open locks at this time ("+List.arrayToList(locks, ", ")+").";
089                */
090                
091                // Requests
092                Query req=new QueryImpl(new Collection.Key[]{KeyConstants._web,KeyConstants._uri,START_TIME,KeyConstants._timeout}, 0, "requests");
093                sct.setEL(KeyConstants._requests, req);
094                
095                // Template Cache
096                Query tc=new QueryImpl(new Collection.Key[]{KeyConstants._web,ELEMENTS,KeyConstants._size}, 0, "templateCache");
097                sct.setEL(KeyImpl.init("templateCache"), tc);
098                
099                // Scopes 
100                Struct scopes=new StructImpl();
101                sct.setEL(KeyConstants._scopes, scopes);
102                Query app=new QueryImpl(new Collection.Key[]{KeyConstants._web,KeyConstants._application,ELEMENTS,KeyConstants._size}, 0, "templateCache");
103                scopes.setEL(KeyConstants._application, app);
104                Query sess=new QueryImpl(new Collection.Key[]{KeyConstants._web,KeyConstants._application,USERS,ELEMENTS,KeyConstants._size}, 0, "templateCache");
105                scopes.setEL(KeyConstants._session, sess);
106
107                // Query
108                Query qry=new QueryImpl(new Collection.Key[]{KeyConstants._web,KeyConstants._application,START_TIME,KeyConstants._sql}, 0, "requests");
109                sct.setEL(QUERIES, qry);
110                
111                // Locks
112                Query lck=new QueryImpl(new Collection.Key[]{KeyConstants._web,KeyConstants._application,KeyConstants._name,START_TIME,KeyConstants._timeout,KeyConstants._type}, 0, "requests");
113                sct.setEL(LOCKS, lck);
114
115                // Loop webs
116                ConfigWebImpl web;
117                Map<Integer, PageContextImpl> pcs;
118                PageContextImpl _pc;
119                int row,openConnections=0;
120                CFMLFactoryImpl factory;
121                ActiveQuery[] queries;
122                ActiveQuery aq;
123                ActiveLock[] locks;
124                ActiveLock al;
125                for(int i=0;i<webs.length;i++){
126                        
127                        // Loop requests
128                        web=(ConfigWebImpl) webs[i];
129                        factory=(CFMLFactoryImpl)web.getFactory();
130                        pcs = factory.getActivePageContexts();
131                        Iterator<PageContextImpl> it = pcs.values().iterator();
132                        while(it.hasNext()){
133                                _pc = it.next();
134                                if(_pc.isGatewayContext()) continue;
135                                
136                                // Request
137                                row = req.addRow();
138                                req.setAt(KeyConstants._web, row, web.getLabel());
139                                req.setAt(KeyConstants._uri, row, getPath(_pc.getHttpServletRequest()));
140                                req.setAt(START_TIME, row, new DateTimeImpl(pc.getStartTime(),false));
141                                req.setAt(KeyConstants._timeout, row, new Double(pc.getRequestTimeout()));
142                                
143                                // Query
144                                queries = _pc.getActiveQueries();
145                                if(queries!=null) {
146                                        for(int y=0;y<queries.length;y++){
147                                                aq=queries[y];
148                                                row = qry.addRow();
149                                                qry.setAt(KeyConstants._web, row, web.getLabel());
150                                                qry.setAt(KeyConstants._application, row, _pc.getApplicationContext().getName());
151                                                qry.setAt(START_TIME, row, new DateTimeImpl(web,aq.startTime,true));
152                                                qry.setAt(KeyConstants._sql, row, aq.sql);
153                                        }
154                                }
155                                
156                                // Lock
157                                locks = _pc.getActiveLocks();
158                                if(locks!=null) {
159                                        for(int y=0;y<locks.length;y++){
160                                                al=locks[y];
161                                                row = lck.addRow();
162                                                lck.setAt(KeyConstants._web, row, web.getLabel());
163                                                lck.setAt(KeyConstants._application, row, _pc.getApplicationContext().getName());
164                                                lck.setAt(KeyConstants._name, row, al.name);
165                                                lck.setAt(START_TIME, row, new DateTimeImpl(web,al.startTime,true));
166                                                lck.setAt(KeyConstants._timeout, row, Caster.toDouble(al.timeoutInMillis/1000));
167                                                lck.setAt(KeyConstants._type, row, al.type==LockManager.TYPE_EXCLUSIVE?"exclusive":"readonly");
168                                        }
169                                }
170                        }
171                        openConnections+=web.getDatasourceConnectionPool().openConnections();
172
173
174                        // Template Cache
175                        Mapping[] mappings = ConfigWebUtil.getAllMappings(web);
176                        long[] tce = templateCacheElements(mappings);
177                        row = tc.addRow();
178                        tc.setAt(KeyConstants._web, row, web.getLabel());
179                        tc.setAt(KeyConstants._size, row, new Double(tce[1]));
180                        tc.setAt(ELEMENTS, row, new Double(tce[0]));
181                        
182                        // Scope Application
183                        getAllApplicationScopes(web,factory.getScopeContext(),app);
184                        getAllCFSessionScopes(web,factory.getScopeContext(),sess);
185                        
186                        
187                }
188                
189                // Datasource
190                Struct ds=new StructImpl();
191                sct.setEL(KeyConstants._datasources, ds);
192                
193                ds.setEL(CACHED_QUERIES, Caster.toDouble(ConfigWebUtil.getCacheHandlerFactories(pc.getConfig()).query.size(pc))); // there is only one cache for all contexts
194                ds.setEL(OPEN_CONNECTIONS, Caster.toDouble(openConnections));
195                
196                // Memory
197                Struct mem=new StructImpl();
198                sct.setEL(KeyConstants._memory, mem);
199                mem.setEL("heap", SystemUtil.getMemoryUsageAsStruct(SystemUtil.MEMORY_TYPE_HEAP));
200                mem.setEL("nonheap", SystemUtil.getMemoryUsageAsStruct(SystemUtil.MEMORY_TYPE_NON_HEAP));
201                
202                
203                // uptime
204                sct.set("uptime", new DateTimeImpl(engine.uptime(),true));
205                
206                // now
207                sct.set("now", new DateTimeImpl(pc));
208                
209                
210                //SizeAndCount.Size size = SizeAndCount.sizeOf(pc.serverScope());
211                
212                
213                
214                return sct;
215    }
216        
217        private static void getAllApplicationScopes(ConfigWebImpl web, ScopeContext sc, Query app) throws PageException {
218                Struct all = sc.getAllApplicationScopes();
219                Iterator<Entry<Key, Object>> it = all.entryIterator();
220                Entry<Key, Object> e;
221                int row;
222                Size sac;
223                while(it.hasNext()){
224                        e = it.next();
225                        row=app.addRow();
226                        sac = SizeAndCount.sizeOf(e.getValue());
227                        app.setAt(KeyConstants._web, row, web.getLabel());
228                        app.setAt(KeyConstants._application, row, e.getKey().getString());
229                        app.setAt(KeyConstants._size, row, new Double(sac.size));
230                        app.setAt(ELEMENTS, row, new Double(sac.count));
231                        
232                }
233        }
234        
235        private static void getAllCFSessionScopes(ConfigWebImpl web, ScopeContext sc, Query sess) throws PageException {
236                Struct all = sc.getAllCFSessionScopes();
237                Iterator it = all.entryIterator(),itt;
238                Entry e,ee;
239                int row,size,count,users;
240                Size sac;
241                // applications
242                while(it.hasNext()){
243                        e = (Entry) it.next();
244                        itt = ((Map)e.getValue()).entrySet().iterator();
245                        size=0;count=0;users=0;
246                        while(itt.hasNext()){
247                                ee=(Entry)itt.next();
248                                sac = SizeAndCount.sizeOf(ee.getValue());
249                                size+=sac.size;
250                                count+=sac.count;
251                                users++;
252                        }
253                        row=sess.addRow();
254                        
255                        sess.setAt(KeyConstants._web, row, web.getLabel());
256                        sess.setAt(USERS, row, new Double(users));
257                        sess.setAt(KeyConstants._application, row, e.getKey().toString());
258                        sess.setAt(KeyConstants._size, row, new Double(size));
259                        sess.setAt(ELEMENTS, row, new Double(count));
260                }
261        }
262        
263        private static long[] templateCacheElements(Mapping[] mappings) {
264                long elements=0,size=0;
265                
266                PageSourcePool psp;
267                Object[] keys;
268                PageSourceImpl ps;
269                Resource res;
270                MappingImpl mapping;
271                for(int i=0;i<mappings.length;i++){
272                        mapping=(MappingImpl)mappings[i];
273                        psp = mapping.getPageSourcePool();
274                        keys = psp.keys();
275                        for(int y=0;y<keys.length;y++)       {
276                                ps = (PageSourceImpl) psp.getPageSource(keys[y], false);
277                                if(ps.isLoad()) {
278                                        elements++;
279                                        res=mapping.getClassRootDirectory().getRealResource(ps.getJavaName()+".class");
280                                        size+=res.length();
281                                }
282                        }
283                }
284                return new long[]{elements,size};
285        }
286        
287        
288        public static String getScriptName(HttpServletRequest req) {
289                return emptyIfNull(req.getContextPath())+emptyIfNull(req.getServletPath());
290        }
291
292        public static String getPath(HttpServletRequest req) {
293                String qs=emptyIfNull(req.getQueryString());
294                if(qs.length()>0)qs="?"+qs;
295                        
296                        
297                return emptyIfNull(req.getContextPath())+emptyIfNull(req.getServletPath())+qs;
298        }
299
300        private static String emptyIfNull(String str) {
301                if(str==null) return "";
302                return str;
303        }
304}