001    package railo.runtime.config;
002    
003    import java.io.File;
004    import java.io.IOException;
005    import java.net.MalformedURLException;
006    import java.net.URL;
007    import java.util.ArrayList;
008    import java.util.Arrays;
009    import java.util.HashMap;
010    import java.util.Iterator;
011    import java.util.List;
012    import java.util.Map;
013    
014    import railo.commons.collections.HashTable;
015    import railo.commons.io.SystemUtil;
016    import railo.commons.io.res.Resource;
017    import railo.commons.io.res.ResourcesImpl;
018    import railo.commons.lang.ClassUtil;
019    import railo.commons.lang.PCLCollection;
020    import railo.commons.lang.StringUtil;
021    import railo.commons.lang.SystemOut;
022    import railo.loader.TP;
023    import railo.loader.engine.CFMLEngine;
024    import railo.loader.engine.CFMLEngineFactory;
025    import railo.loader.util.ExtensionFilter;
026    import railo.runtime.CFMLFactory;
027    import railo.runtime.CFMLFactoryImpl;
028    import railo.runtime.Mapping;
029    import railo.runtime.MappingImpl;
030    import railo.runtime.engine.CFMLEngineImpl;
031    import railo.runtime.engine.ThreadQueueImpl;
032    import railo.runtime.exp.ApplicationException;
033    import railo.runtime.exp.PageException;
034    import railo.runtime.monitor.ActionMonitorCollector;
035    import railo.runtime.monitor.IntervallMonitor;
036    import railo.runtime.monitor.RequestMonitor;
037    import railo.runtime.net.http.ReqRspUtil;
038    import railo.runtime.op.Caster;
039    import railo.runtime.reflection.Reflector;
040    import railo.runtime.security.SecurityManager;
041    import railo.runtime.security.SecurityManagerImpl;
042    import railo.runtime.type.scope.Cluster;
043    import railo.runtime.type.scope.ClusterRemote;
044    import railo.runtime.type.scope.ClusterWrap;
045    import railo.runtime.type.util.ArrayUtil;
046    
047    /**
048     * config server impl
049     */
050    public final class ConfigServerImpl extends ConfigImpl implements ConfigServer {
051        
052    
053            private final CFMLEngineImpl engine;
054        private Map<String,CFMLFactory> initContextes;
055        //private Map contextes;
056        private SecurityManager defaultSecurityManager;
057        private Map managers=new HashTable();
058        private String defaultPassword;
059        private Resource rootDir;
060        private URL updateLocation;
061        private String updateType="";
062            private ConfigListener configListener;
063            private Map<String, String> labels;
064            private RequestMonitor[] requestMonitors;
065            private IntervallMonitor[] intervallMonitors;
066            private ActionMonitorCollector actionMonitorCollector;
067            
068            private boolean monitoringEnabled=false;
069            private int delay=0;
070            private boolean captcha=false;
071            private static ConfigServerImpl instance;
072            
073            /**
074         * @param engine 
075         * @param initContextes
076         * @param contextes
077         * @param configDir
078         * @param configFile
079         */
080        protected ConfigServerImpl(CFMLEngineImpl engine,Map<String,CFMLFactory> initContextes, Map<String,CFMLFactory> contextes, Resource configDir, Resource configFile) {
081            super(null,configDir, configFile);
082            this.engine=engine;
083            this.initContextes=initContextes;
084            //this.contextes=contextes;
085            this.rootDir=configDir;
086            instance=this;
087        }
088            
089        /**
090             * @return the configListener
091             */
092            public ConfigListener getConfigListener() {
093                    return configListener;
094            }
095    
096            /**
097             * @param configListener the configListener to set
098             */
099            public void setConfigListener(ConfigListener configListener) {
100                    this.configListener = configListener;
101            }
102    
103        @Override
104        public ConfigServer getConfigServer(String password) {
105            return this;
106        }
107    
108        @Override
109        public ConfigWeb[] getConfigWebs() {
110        
111            Iterator<String> it = initContextes.keySet().iterator();
112            ConfigWeb[] webs=new ConfigWeb[initContextes.size()];
113            int index=0;        
114            while(it.hasNext()) {
115                webs[index++]=((CFMLFactoryImpl)initContextes.get(it.next())).getConfig();
116            }
117            return webs;
118        }
119        
120        @Override
121        public ConfigWeb getConfigWeb(String realpath) {
122            return getConfigWebImpl(realpath);
123        }
124        
125        /**
126         * returns CongigWeb Implementtion
127         * @param realpath
128         * @return ConfigWebImpl
129         */
130        protected ConfigWebImpl getConfigWebImpl(String realpath) {
131            Iterator<String> it = initContextes.keySet().iterator();
132            while(it.hasNext()) {
133                ConfigWebImpl cw=((CFMLFactoryImpl)initContextes.get(it.next())).getConfigWebImpl();
134                if(ReqRspUtil.getRootPath(cw.getServletContext()).equals(realpath))
135                    return cw;
136            }
137            return null;
138        }
139        
140        public ConfigWebImpl getConfigWebById(String id) {
141            Iterator<String> it = initContextes.keySet().iterator();
142              
143            while(it.hasNext()) {
144                ConfigWebImpl cw=((CFMLFactoryImpl)initContextes.get(it.next())).getConfigWebImpl();
145                if(cw.getId().equals(id))
146                    return cw;
147            }
148            return null;
149        }
150        
151        /**
152         * @return JspFactoryImpl array
153         */
154        public CFMLFactoryImpl[] getJSPFactories() {
155            Iterator<String> it = initContextes.keySet().iterator();
156            CFMLFactoryImpl[] factories=new CFMLFactoryImpl[initContextes.size()];
157            int index=0;        
158            while(it.hasNext()) {
159                factories[index++]=(CFMLFactoryImpl)initContextes.get(it.next());
160            }
161            return factories;
162        }
163        @Override
164        public Map<String,CFMLFactory> getJSPFactoriesAsMap() {
165            return initContextes;
166        }
167    
168        @Override
169        public SecurityManager getSecurityManager(String id) {
170            Object o=managers.get(id);
171            if(o!=null) return (SecurityManager) o;
172            if(defaultSecurityManager==null) {
173                    defaultSecurityManager = SecurityManagerImpl.getOpenSecurityManager();
174            }
175            return defaultSecurityManager.cloneSecurityManager();
176        }
177        
178        @Override
179        public boolean hasIndividualSecurityManager(String id) {
180            return managers.containsKey(id);
181        }
182    
183        /**
184         * @param defaultSecurityManager
185         */
186        protected void setDefaultSecurityManager(SecurityManager defaultSecurityManager) {
187            this.defaultSecurityManager=defaultSecurityManager;
188        }
189    
190        /**
191         * @param id
192         * @param securityManager
193         */
194        protected void setSecurityManager(String id, SecurityManager securityManager) {
195            managers.put(id,securityManager);
196        }
197    
198        /**
199         * @param id
200         */
201        protected void removeSecurityManager(String id) {
202            managers.remove(id);
203        }
204        
205        @Override
206        public SecurityManager getDefaultSecurityManager() {
207            return defaultSecurityManager;
208        }
209        /**
210         * @return Returns the defaultPassword.
211         */
212        protected String getDefaultPassword() {
213            return defaultPassword;
214        }
215        /**
216         * @param defaultPassword The defaultPassword to set.
217         */
218        protected void setDefaultPassword(String defaultPassword) {
219            this.defaultPassword = defaultPassword;
220        }
221    
222        @Override
223        public CFMLEngine getCFMLEngine() {
224            return engine;
225        }
226    
227    
228        /**
229         * @return Returns the rootDir.
230         */
231        public Resource getRootDirectory() {
232            return rootDir;
233        }
234    
235        @Override
236        public String getUpdateType() {
237            return updateType;
238        }
239    
240        @Override
241        public void setUpdateType(String updateType) {
242            if(!StringUtil.isEmpty(updateType))
243                this.updateType = updateType;
244        }
245    
246        @Override
247        public URL getUpdateLocation() {
248            return updateLocation;
249        }
250    
251        @Override
252        public void setUpdateLocation(URL updateLocation) {
253            this.updateLocation = updateLocation;
254        }
255    
256        @Override
257        public void setUpdateLocation(String strUpdateLocation) throws MalformedURLException {
258            setUpdateLocation(new URL(strUpdateLocation));
259        }
260    
261        @Override
262        public void setUpdateLocation(String strUpdateLocation, URL defaultValue) {
263            try {
264                setUpdateLocation(strUpdateLocation);
265            } catch (MalformedURLException e) {
266                setUpdateLocation(defaultValue);
267            }
268        }
269    
270        @Override
271        public SecurityManager getSecurityManager() {
272            SecurityManagerImpl sm = (SecurityManagerImpl) getDefaultSecurityManager();//.cloneSecurityManager();
273            //sm.setAccess(SecurityManager.TYPE_ACCESS_READ,SecurityManager.ACCESS_PROTECTED);
274            //sm.setAccess(SecurityManager.TYPE_ACCESS_WRITE,SecurityManager.ACCESS_PROTECTED);
275            return sm;
276        }
277    
278            /**
279             * @return the instance
280             */
281            public static ConfigServerImpl getInstance() {
282                    return instance;
283            }
284    
285            public void setLabels(Map<String, String> labels) {
286                    this.labels=labels;
287            }
288            public Map<String, String> getLabels() {
289                    if(labels==null) labels=new HashMap<String, String>();
290                    return labels;
291            }
292    
293            
294            private ThreadQueueImpl threadQueue;
295            protected void setThreadQueue(ThreadQueueImpl threadQueue) {
296                    this.threadQueue=threadQueue;
297            }
298            public ThreadQueueImpl getThreadQueue() {
299                    return threadQueue;
300            }
301            
302            public RequestMonitor[] getRequestMonitors() {
303                    return requestMonitors;
304            }
305            
306            public RequestMonitor getRequestMonitor(String name) throws ApplicationException {
307                    for(int i=0;i<requestMonitors.length;i++){
308                            if(requestMonitors[i].getName().equalsIgnoreCase(name))
309                                    return requestMonitors[i];
310                    }
311                    throw new ApplicationException("there is no request monitor registered with name ["+name+"]");
312            }
313    
314            protected void setRequestMonitors(RequestMonitor[] monitors) {
315                    this.requestMonitors=monitors;;
316            }
317            public IntervallMonitor[] getIntervallMonitors() {
318                    return intervallMonitors;
319            }
320    
321            public IntervallMonitor getIntervallMonitor(String name) throws ApplicationException {
322                    for(int i=0;i<intervallMonitors.length;i++){
323                            if(intervallMonitors[i].getName().equalsIgnoreCase(name))
324                                    return intervallMonitors[i];
325                    }
326                    throw new ApplicationException("there is no intervall monitor registered with name ["+name+"]");
327            }
328    
329            protected void setIntervallMonitors(IntervallMonitor[] monitors) {
330                    this.intervallMonitors=monitors;;
331            }
332            
333    
334            public void setActionMonitorCollector(ActionMonitorCollector actionMonitorCollector) {
335                    this.actionMonitorCollector=actionMonitorCollector;
336            }
337            
338            public ActionMonitorCollector getActionMonitorCollector() {
339                    return actionMonitorCollector;
340            }
341            
342            public Object getActionMonitor(String name) { // FUTURE return ActionMonitor
343                    return actionMonitorCollector.getActionMonitor(name);
344            }
345    
346            @Override
347            public boolean isMonitoringEnabled() {
348                    return monitoringEnabled;
349            }
350    
351            protected void setMonitoringEnabled(boolean monitoringEnabled) {
352                    this.monitoringEnabled=monitoringEnabled;;
353            }
354    
355    
356            protected void setLoginDelay(int delay) {
357                    this.delay=delay;
358            }
359    
360            protected void setLoginCaptcha(boolean captcha) {
361                    this.captcha=captcha;
362            }
363    
364            @Override
365            public int getLoginDelay() {
366                    return delay;
367            }
368    
369            @Override
370            public boolean getLoginCaptcha() {
371                    return captcha;
372            }
373    
374        public void reset() {
375            super.reset();
376            getThreadQueue().clear();
377        }
378        
379        @Override
380            public Resource getSecurityDirectory(){
381            Resource cacerts=null;
382            // javax.net.ssl.trustStore
383            String trustStore = SystemUtil.getPropertyEL("javax.net.ssl.trustStore");
384            if(trustStore!=null){
385                    cacerts = ResourcesImpl.getFileResourceProvider().getResource(trustStore);
386            }
387            
388            // security/cacerts
389            if(cacerts==null || !cacerts.exists()) {
390                    cacerts = getConfigDir().getRealResource("security/cacerts");
391                    if(!cacerts.exists())cacerts.mkdirs();
392            }
393            return cacerts;
394            }
395        
396        @Override
397            public void checkPermGenSpace(boolean check) {
398            //print.e(Runtime.getRuntime().freeMemory());
399                    // Runtime.getRuntime().freeMemory()<200000 || 
400            // long pgs=SystemUtil.getFreePermGenSpaceSize();
401            int promille=SystemUtil.getFreePermGenSpacePromille();
402            
403            // Pen Gen Space info not available 
404            if(promille==-1) {//if(pgs==-1) {
405                    if(countLoadedPages()>500)
406                            shrink();
407            }
408            else if(!check || promille<50){//else if(!check || pgs<1024*1024){
409                            SystemOut.printDate(getErrWriter(),"+Free Perm Gen Space is less than 1mb (free:"+((SystemUtil.getFreePermGenSpaceSize())/1024)+"kb), shrink all template classloaders");
410                            // first just call GC and check if it help
411                            System.gc();
412                            //if(SystemUtil.getFreePermGenSpaceSize()>1024*1024) 
413                            if(SystemUtil.getFreePermGenSpacePromille()>50) 
414                                    return;
415                            
416                            shrink();
417                    }
418            }
419        
420        private void shrink() {
421            ConfigWeb[] webs = getConfigWebs();
422                    int count=0;
423                    for(int i=0;i<webs.length;i++){
424                            count+=shrink((ConfigWebImpl) webs[i],false);
425                    }
426                    if(count==0) {
427                            for(int i=0;i<webs.length;i++){
428                                    shrink((ConfigWebImpl) webs[i],true);
429                            }
430                    }
431            }
432    
433            private static int shrink(ConfigWebImpl config, boolean force) {
434                    int count=0;
435                    count+=shrink(config.getMappings(),force);
436                    count+=shrink(config.getCustomTagMappings(),force);
437                    count+=shrink(config.getComponentMappings(),force);
438                    count+=shrink(config.getFunctionMapping(),force);
439                    count+=shrink(config.getServerFunctionMapping(),force);
440                    count+=shrink(config.getTagMapping(),force);
441                    count+=shrink(config.getServerTagMapping(),force);
442                    //count+=shrink(config.getServerTagMapping(),force);
443                    return count;
444            }
445    
446            private static int shrink(Mapping[] mappings, boolean force) {
447                    int count=0;
448                    for(int i=0;i<mappings.length;i++){
449                            count+=shrink(mappings[i],force);
450                    }
451                    return count;
452            }
453    
454            private static int shrink(Mapping mapping, boolean force) {
455                    try {
456                            PCLCollection pcl = ((MappingImpl)mapping).getPCLCollection();
457                            if(pcl!=null)return pcl.shrink(force);
458                    } 
459                    catch (Throwable t) {
460                            t.printStackTrace();
461                    }
462                    return 0;
463            }
464    
465            
466             public long countLoadedPages() {
467                     long count=0;
468                     ConfigWeb[] webs = getConfigWebs();
469                            for(int i=0;i<webs.length;i++){
470                    count+=_count((ConfigWebImpl) webs[i]);
471                    }       
472                    return count;
473             }
474             private static long _count(ConfigWebImpl config) {
475                     long count=0;
476                    count+=_count(config.getMappings());
477                    count+=_count(config.getCustomTagMappings());
478                    count+=_count(config.getComponentMappings());
479                    count+=_count(config.getFunctionMapping());
480                    count+=_count(config.getServerFunctionMapping());
481                    count+=_count(config.getTagMapping());
482                    count+=_count(config.getServerTagMapping());
483                    //count+=_count(((ConfigWebImpl)config).getServerTagMapping());
484                    return count;
485            }
486    
487             private static long _count(Mapping[] mappings) {
488                     long count=0;
489                    for(int i=0;i<mappings.length;i++){
490                            count+=_count(mappings[i]);
491                    }
492                    return count;
493            }
494    
495            private static long _count(Mapping mapping) {
496                    PCLCollection pcl = ((MappingImpl)mapping).getPCLCollection();
497                    return pcl==null?0:pcl.count();
498            }
499    
500            @Override
501            public Cluster createClusterScope() throws PageException {
502                    Cluster cluster=null;
503                    try {
504                    if(Reflector.isInstaneOf(getClusterClass(), Cluster.class)){
505                            cluster=(Cluster) ClassUtil.loadInstance(
506                                            getClusterClass(),
507                                                    ArrayUtil.OBJECT_EMPTY
508                                                    );
509                            cluster.init(this);
510                    }
511                    else if(Reflector.isInstaneOf(getClusterClass(), ClusterRemote.class)){
512                            ClusterRemote cb=(ClusterRemote) ClassUtil.loadInstance(
513                                            getClusterClass(),
514                                                    ArrayUtil.OBJECT_EMPTY
515                                                    );
516                            
517                            cluster=new ClusterWrap(this,cb);
518                            //cluster.init(cs);
519                    }
520                    } 
521            catch (Exception e) {
522                            throw Caster.toPageException(e);
523                    }
524            return cluster;
525            }
526    
527            @Override
528            public boolean hasServerPassword() {
529                    return hasPassword();
530            }
531    
532            public String[] getInstalledPatches() throws PageException {
533                    CFMLEngineFactory factory = getCFMLEngine().getCFMLEngineFactory();
534            
535                    try{
536                            return factory.getInstalledPatches();
537                    }
538                    catch(Throwable t){
539                            try {
540                                    return getInstalledPatchesOld(factory);
541                            } catch (Exception e1) {
542                                    throw Caster.toPageException(e1);
543                            }
544                    }
545            }
546            
547            private String[] getInstalledPatchesOld(CFMLEngineFactory factory) throws IOException { 
548                    File patchDir = new File(factory.getResourceRoot(),"patches");
549            if(!patchDir.exists())patchDir.mkdirs();
550            
551                    File[] patches=patchDir.listFiles(new ExtensionFilter(new String[]{"."+getCoreExtension()}));
552            
553            List<String> list=new ArrayList<String>();
554            String name;
555            int extLen=getCoreExtension().length()+1;
556            for(int i=0;i<patches.length;i++) {
557                    name=patches[i].getName();
558                    name=name.substring(0, name.length()-extLen);
559                     list.add(name);
560            }
561            String[] arr = list.toArray(new String[list.size()]);
562            Arrays.sort(arr);
563            return arr;
564            }
565    
566            
567            private String getCoreExtension()  {
568            URL res = new TP().getClass().getResource("/core/core.rcs");
569            if(res!=null) return "rcs";
570            
571            res = new TP().getClass().getResource("/core/core.rc");
572            if(res!=null) return "rc";
573            
574            return "rc";
575            }
576    
577            @Override
578            public boolean allowRequestTimeout() {
579                    return engine.allowRequestTimeout();
580            }
581            
582    
583            private boolean fullNullSupport=false;
584            protected void setFullNullSupport(boolean fullNullSupport) {
585                    this.fullNullSupport=fullNullSupport;
586            }
587    
588            public boolean getFullNullSupport() {
589                    return fullNullSupport;
590            }
591    }