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.tag;
020
021import java.nio.charset.Charset;
022import java.util.Locale;
023import java.util.TimeZone;
024
025import lucee.commons.date.TimeZoneUtil;
026import lucee.commons.io.CharsetUtil;
027import lucee.commons.io.res.Resource;
028import lucee.commons.io.res.util.ResourceUtil;
029import lucee.commons.lang.ClassException;
030import lucee.commons.lang.StringUtil;
031import lucee.runtime.Mapping;
032import lucee.runtime.config.Config;
033import lucee.runtime.config.ConfigWebUtil;
034import lucee.runtime.exp.ApplicationException;
035import lucee.runtime.exp.ExpressionException;
036import lucee.runtime.exp.PageException;
037import lucee.runtime.ext.tag.TagImpl;
038import lucee.runtime.i18n.LocaleFactory;
039import lucee.runtime.listener.AppListenerUtil;
040import lucee.runtime.listener.ApplicationContextPro;
041import lucee.runtime.listener.ClassicApplicationContext;
042import lucee.runtime.op.Caster;
043import lucee.runtime.orm.ORMUtil;
044import lucee.runtime.type.Struct;
045import lucee.runtime.type.StructImpl;
046import lucee.runtime.type.UDF;
047import lucee.runtime.type.dt.TimeSpan;
048import lucee.runtime.type.scope.Scope;
049import lucee.runtime.type.scope.UndefinedImpl;
050
051/**
052* Defines scoping for a CFML application, enables or disables storing client variables, 
053*                       and specifies a client variable storage mechanism. 
054*                       By default, client variables are disabled. Also, enables session variables and sets timeouts 
055*                       for session and application variables. Session and application variables are stored in memory.
056*
057*
058*
059**/
060public final class Application extends TagImpl {
061
062        
063
064        private static final int ACTION_CREATE = 0;
065        private static final int ACTION_UPDATE = 1;
066    
067        private Boolean setClientCookies;
068        private Boolean setDomainCookies;
069        private Boolean setSessionManagement;
070        private String clientstorage;
071        private String sessionstorage;
072        private Boolean setClientManagement;
073        private TimeSpan applicationTimeout;
074        private TimeSpan sessionTimeout;
075        private TimeSpan clientTimeout;
076        private TimeSpan requestTimeout;
077        private Mapping[] mappings;
078        private Mapping[] customTagMappings;
079        private Mapping[] componentMappings;
080        private String secureJsonPrefix;
081        private Boolean bufferOutput;
082        private Boolean secureJson;
083        private String scriptrotect;
084        private Boolean typeChecking;
085        private Object datasource;
086        private Object defaultdatasource;
087        private int loginstorage=Scope.SCOPE_UNDEFINED;
088        
089        //ApplicationContextImpl appContext;
090    private String name="";
091        private int action=ACTION_CREATE;
092        private int localMode=-1;
093        private Locale locale;
094        private TimeZone timeZone;
095        private Charset webCharset;
096        private Charset resourceCharset;
097        private short sessionType=-1;
098        private short wsType=-1;
099        private boolean sessionCluster;
100        private boolean clientCluster;
101        private Boolean compression;
102
103        private Boolean ormenabled;
104        private Struct ormsettings;
105        private Struct tag;
106        private Struct s3;
107        
108        private Boolean triggerDataMember=null;
109        private String cacheFunction;
110        private String cacheQuery;
111        private String cacheTemplate;
112        private String cacheInclude;
113        private String cacheObject;
114        private String cacheResource;
115        private Struct datasources;
116        private UDF onmissingtemplate;
117        private short scopeCascading=-1;
118        private Boolean suppress;
119        private boolean cgiReadOnly=true;
120        
121     
122    @Override
123    public void release() {
124        super.release();
125        setClientCookies=null;
126        setDomainCookies=null;
127        setSessionManagement=null;
128        clientstorage=null;
129        sessionstorage=null;
130        setClientManagement=null;
131        sessionTimeout=null;
132        clientTimeout=null;
133        requestTimeout=null;
134        applicationTimeout=null;
135        mappings=null;
136        customTagMappings=null;
137        componentMappings=null;
138        bufferOutput=null;
139        secureJson=null;
140        secureJsonPrefix=null;
141        typeChecking=null;
142        suppress=null;
143        loginstorage=Scope.SCOPE_UNDEFINED;
144        scriptrotect=null;
145        datasource=null;
146        defaultdatasource=null;
147        datasources=null;
148        this.name="";
149        action=ACTION_CREATE;
150        localMode=-1;
151        locale=null;
152        timeZone=null;
153        webCharset=null;
154        resourceCharset=null;
155        sessionType=-1;
156        wsType=-1;
157        sessionCluster=false;
158        clientCluster=false;
159        compression=null;
160        
161        ormenabled=null;
162        ormsettings=null;
163        tag=null;
164        s3=null;
165        //appContext=null;
166        
167        triggerDataMember=null;
168        cgiReadOnly=true;
169
170        cacheFunction=null;
171        cacheQuery=null;
172        cacheTemplate=null;
173        cacheObject=null;
174        cacheResource=null;
175        cacheInclude=null;
176        onmissingtemplate=null;
177        scopeCascading=-1;
178    }
179    
180    /** set the value setclientcookies
181        *  Yes or No. Yes enables client cookies. Default is Yes. If you set this attribute to 
182        *               "No", CFML does not automatically send the CFID and CFTOKEN cookies to the client browser;
183        *               you must manually code CFID and CFTOKEN on the URL for every page that uses Session or Client variables.
184        * @param setClientCookies value to set
185        **/
186        public void setSetclientcookies(boolean setClientCookies)       {
187                this.setClientCookies=setClientCookies?Boolean.TRUE:Boolean.FALSE;
188            //getAppContext().setSetClientCookies(setClientCookies);
189        }
190
191    /** set the value setdomaincookies
192        *  Yes or No. Sets the CFID and CFTOKEN cookies for a domain, not just a single host. 
193        *               Applications that are running on clusters must set this value to Yes. The default is No.
194        * @param setDomainCookies value to set
195        **/
196        public void setSetdomaincookies(boolean setDomainCookies)       {
197                this.setDomainCookies=setDomainCookies?Boolean.TRUE:Boolean.FALSE;
198        }
199        
200        public void setCgireadonly(boolean cgiReadOnly) {
201                this.cgiReadOnly=cgiReadOnly;
202        }
203
204        /** set the value sessionmanagement
205        *  Yes or No. Yes enables session variables. Default is No.
206        * @param setSessionManagement value to set
207        **/
208        public void setSessionmanagement(boolean setSessionManagement)  {
209                this.setSessionManagement=setSessionManagement?Boolean.TRUE:Boolean.FALSE;
210            //getAppContext().setSetSessionManagement(setSessionManagement);
211        }
212
213    
214        /**
215         * @param datasource the datasource to set
216         * @throws PageException 
217         */
218        public void setDatasource(Object datasource) throws PageException {
219                this.datasource = AppListenerUtil.toDefaultDatasource(datasource);
220        }
221        
222        public void setDefaultdatasource(Object defaultdatasource) throws PageException {
223                this.defaultdatasource =  AppListenerUtil.toDefaultDatasource(defaultdatasource);
224        }
225        
226        public void setDatasources(Struct datasources) {
227                this.datasources = datasources;
228        }
229        
230        public void setLocalmode(String strLocalMode) throws ApplicationException {
231                this.localMode = AppListenerUtil.toLocalMode(strLocalMode);
232                
233        }
234        
235        public void setTimezone(String strTimeZone) throws ExpressionException {
236                if(StringUtil.isEmpty(strTimeZone)) return;
237                this.timeZone = TimeZoneUtil.toTimeZone(strTimeZone);
238                
239        }
240        
241        public void setScopecascading(String scopeCascading) throws ApplicationException {
242                if(StringUtil.isEmpty(scopeCascading)) return;
243                short NULL=-1;
244                short tmp = ConfigWebUtil.toScopeCascading(scopeCascading,NULL);
245                if(tmp==NULL) throw new ApplicationException("invalid value ("+scopeCascading+") for attribute [ScopeCascading], valid values are [strict,small,standard]");
246                this.scopeCascading=tmp;
247        }
248        
249        public void setWebcharset(String charset) {
250                if(StringUtil.isEmpty(charset)) return;
251                webCharset = CharsetUtil.toCharset(charset);
252                
253        }
254        
255        public void setResourcecharset(String charset) {
256                if(StringUtil.isEmpty(charset)) return;
257                resourceCharset = CharsetUtil.toCharset(charset);
258                
259        }
260        
261        public void setLocale(String strLocale) throws ExpressionException {
262                if(StringUtil.isEmpty(strLocale)) return;
263                this.locale = LocaleFactory.getLocale(strLocale);
264                
265        }
266
267        /** set the value clientstorage
268        *  Specifies how Lucee stores client variables
269        * @param clientstorage value to set
270        **/
271        public void setClientstorage(String clientstorage)      {
272                this.clientstorage=clientstorage;
273        }
274
275        public void setSessionstorage(String sessionstorage)    {
276                this.sessionstorage=sessionstorage;
277        }
278
279        /** set the value clientmanagement
280        *  Yes or No. Enables client variables. Default is No.
281        * @param setClientManagement value to set
282        **/
283        public void setClientmanagement(boolean setClientManagement)    {
284                this.setClientManagement=setClientManagement?Boolean.TRUE:Boolean.FALSE;
285            //getAppContext().setSetClientManagement(setClientManagement);
286        }
287
288        /** set the value sessiontimeout
289        *  Enter the CreateTimeSpan function and values in days, hours, minutes, and seconds, separated 
290        *               by commas, to specify the lifespan of session variables.
291        * @param sessionTimeout value to set
292        **/
293        public void setSessiontimeout(TimeSpan sessionTimeout)  {
294                this.sessionTimeout=sessionTimeout;
295        }
296        public void setSessiontype(String sessionType) throws ApplicationException      {
297                this.sessionType=AppListenerUtil.toSessionType(sessionType);
298        }
299        public void setWstype(String wstype) throws ApplicationException        {
300                this.wsType=AppListenerUtil.toWSType(wstype);
301        }
302        public void setClientcluster(boolean clientCluster) {
303                this.clientCluster=clientCluster;
304        }
305        public void setSessioncluster(boolean sessionCluster) {
306                this.sessionCluster=sessionCluster;
307        }
308        
309        public void setClienttimeout(TimeSpan clientTimeout)    {
310                this.clientTimeout=clientTimeout;
311        }
312        
313        public void setRequesttimeout(TimeSpan requestTimeout)  {
314                this.requestTimeout=requestTimeout;
315        }
316        
317
318        public void setCachefunction(String cacheFunction)      {
319                if(StringUtil.isEmpty(cacheFunction,true)) return;
320                this.cacheFunction=cacheFunction.trim();
321        }
322        public void setCachequery(String cacheQuery)    {
323                if(StringUtil.isEmpty(cacheQuery,true)) return;
324                this.cacheQuery=cacheQuery.trim();
325        }
326        public void setCachetemplate(String cacheTemplate)      {
327                if(StringUtil.isEmpty(cacheTemplate,true)) return;
328                this.cacheTemplate=cacheTemplate.trim();
329        }
330        public void setCacheinclude(String cacheInclude)        {
331                if(StringUtil.isEmpty(cacheInclude,true)) return;
332                this.cacheInclude=cacheInclude.trim();
333        }
334        public void setCacheobject(String cacheObject)  {
335                if(StringUtil.isEmpty(cacheObject,true)) return;
336                this.cacheObject=cacheObject.trim();
337        }
338        public void setCacheresource(String cacheResource)      {
339                if(StringUtil.isEmpty(cacheResource,true)) return;
340                this.cacheResource=cacheResource.trim();
341        }
342        public void setCompression(boolean compress)    {
343                this.compression=compress;
344        }
345        
346
347        public void setTriggerdatamember(boolean triggerDataMember)     {
348                this.triggerDataMember=triggerDataMember?Boolean.TRUE:Boolean.FALSE;
349        }
350        public void setInvokeimplicitaccessor(boolean invokeimplicitaccessor)   {
351                setTriggerdatamember(invokeimplicitaccessor);
352        }
353
354        /**
355         * @param ormenabled the ormenabled to set
356         */
357        public void setOrmenabled(boolean ormenabled) {
358                this.ormenabled = ormenabled;
359        }
360
361        /**
362         * @param ormsettings the ormsettings to set
363         */
364        public void setOrmsettings(Struct ormsettings) {
365                this.ormsettings = ormsettings;
366        }
367        public void setTag(Struct tag) {
368                this.tag = tag;
369        }
370
371        /**
372         * @param s3 the s3 to set
373         */
374        public void setS3(Struct s3) {
375                this.s3 = s3;
376        }
377
378        /** set the value applicationtimeout
379        *  Enter the CreateTimeSpan function and values in days, hours, minutes, and seconds, separated 
380        *               by commas, to specify the lifespan of application variables. 
381        * @param applicationTimeout value to set
382        **/
383        public void setApplicationtimeout(TimeSpan applicationTimeout)  {
384                this.applicationTimeout=applicationTimeout;
385            //getAppContext().setApplicationTimeout(applicationTimeout);
386        }
387
388        /** set the value name
389        *  The name of your application. This name can be up to 64 characters long.
390        *               Required for application and session variables, optional for client variables
391        * @param name value to set
392        **/
393        public void setName(String name)        {
394            this.name=name;
395        }
396        
397        public void setAction(String strAction) throws ApplicationException     {
398                strAction=strAction.toLowerCase();
399        if(strAction.equals("create"))action=ACTION_CREATE;
400        else if(strAction.equals("update")) action=ACTION_UPDATE;
401        else throw new ApplicationException("invalid action definition ["+strAction+"] for tag application, valid values are [create,update]");
402    
403        }
404        
405        public void setMappings(Struct mappings) throws PageException   {
406            this.mappings=AppListenerUtil.toMappings(pageContext.getConfig(), mappings,getSource());
407                //getAppContext().setMappings(AppListenerUtil.toMappings(pageContext, mappings));
408        }
409        
410        public void setCustomtagpaths(Object mappings) throws PageException     {
411            this.customTagMappings=AppListenerUtil.toCustomTagMappings(pageContext.getConfig(), mappings,getSource());
412        }
413        
414        public void setComponentpaths(Object mappings) throws PageException     {
415            this.componentMappings=AppListenerUtil.toComponentMappings(pageContext.getConfig(), mappings,getSource());
416        }
417        
418
419        public void setSecurejsonprefix(String secureJsonPrefix)        {
420                this.secureJsonPrefix=secureJsonPrefix;
421            //getAppContext().setSecureJsonPrefix(secureJsonPrefix);
422        }
423        public void setSecurejson(boolean secureJson)   {
424                this.secureJson=secureJson?Boolean.TRUE:Boolean.FALSE;
425            //getAppContext().setSecureJson(secureJson);
426        }
427        public void setBufferoutput(boolean bufferOutput)       {
428                this.bufferOutput=bufferOutput?Boolean.TRUE:Boolean.FALSE;
429            //getAppContext().setSecureJson(secureJson);
430        }
431        
432    /**
433     * @param loginstorage The loginstorage to set.
434     * @throws ApplicationException
435     */
436    public void setLoginstorage(String loginstorage) throws ApplicationException {
437        loginstorage=loginstorage.toLowerCase();
438        if(loginstorage.equals("session"))this.loginstorage=Scope.SCOPE_SESSION;
439        else if(loginstorage.equals("cookie"))this.loginstorage=Scope.SCOPE_COOKIE;
440        else throw new ApplicationException("invalid loginStorage definition ["+loginstorage+"] for tag application, valid values are [session,cookie]");
441    }
442        /**
443         * @param scriptrotect the scriptrotect to set
444         */                     
445    public void setScriptprotect(String strScriptrotect) {
446                this.scriptrotect=strScriptrotect;
447        }
448    
449    public void setTypechecking(boolean typeChecking) {
450                this.typeChecking=typeChecking;
451        }
452    
453    public void setSuppressremotecomponentcontent(boolean suppress) {
454                this.suppress=suppress;
455        }
456
457        public void setOnmissingtemplate(Object oUDF) throws PageException {
458                this.onmissingtemplate=Caster.toFunction(oUDF);
459        }
460
461        @Override
462        public int doStartTag() throws PageException    {
463        
464        ApplicationContextPro ac;
465        boolean initORM;
466        if(action==ACTION_CREATE){
467                ac=new ClassicApplicationContext(pageContext.getConfig(),name,false,
468                                pageContext.getCurrentPageSource().getResourceTranslated(pageContext));
469                initORM=set(ac,false);
470                pageContext.setApplicationContext(ac);
471        }
472        else {
473                ac=(ApplicationContextPro) pageContext.getApplicationContext();
474                initORM=set(ac,true);
475        }
476        
477        // scope cascading
478        if(((UndefinedImpl)pageContext.undefinedScope()).getScopeCascadingType()!=ac.getScopeCascading()) {
479                pageContext.undefinedScope().initialize(pageContext);
480            }
481        
482        // ORM
483        if(initORM) ORMUtil.resetEngine(pageContext,false);
484        
485        return SKIP_BODY; 
486        }
487
488        private Resource getSource() throws PageException {
489                return ResourceUtil.getResource(pageContext,pageContext.getCurrentPageSource());
490        }
491
492        private boolean set(ApplicationContextPro ac, boolean update) throws PageException {
493                if(applicationTimeout!=null)                    ac.setApplicationTimeout(applicationTimeout);
494                if(sessionTimeout!=null)                                ac.setSessionTimeout(sessionTimeout);
495                if(clientTimeout!=null)                         ac.setClientTimeout(clientTimeout);
496                if(requestTimeout!=null)                                ac.setRequestTimeout(requestTimeout);
497                if(clientstorage!=null) {
498                        ac.setClientstorage(clientstorage);
499                }
500                if(sessionstorage!=null)        {
501                        ac.setSessionstorage(sessionstorage);
502                }
503                if(customTagMappings!=null)                             ac.setCustomTagMappings(customTagMappings);
504                if(componentMappings!=null)                             ac.setComponentMappings(componentMappings);
505                if(mappings!=null)                                              ac.setMappings(mappings);
506                if(loginstorage!=Scope.SCOPE_UNDEFINED) ac.setLoginStorage(loginstorage);
507                if(!StringUtil.isEmpty(datasource))             {
508                        ac.setDefDataSource(datasource);
509                        ac.setORMDataSource(datasource);
510                }
511                if(!StringUtil.isEmpty(defaultdatasource))ac.setDefDataSource(defaultdatasource);
512                if(datasources!=null){
513                        try {
514                                ac.setDataSources(AppListenerUtil.toDataSources(datasources));
515                        } 
516                        catch (ClassException e) {
517                                throw Caster.toPageException(e);
518                        }
519                }
520                
521                if(onmissingtemplate!=null && ac instanceof ClassicApplicationContext){
522                        ((ClassicApplicationContext)ac).setOnMissingTemplate(onmissingtemplate);
523                }
524
525                if(scriptrotect!=null)                                  ac.setScriptProtect(AppListenerUtil.translateScriptProtect(scriptrotect));
526                if(bufferOutput!=null)                                  ac.setBufferOutput(bufferOutput.booleanValue());
527                if(secureJson!=null)                                    ac.setSecureJson(secureJson.booleanValue());
528                if(typeChecking!=null)                                  ac.setTypeChecking(typeChecking.booleanValue());
529                if(suppress!=null)                                              ac.setSuppressContent(suppress.booleanValue());
530                if(secureJsonPrefix!=null)                              ac.setSecureJsonPrefix(secureJsonPrefix);
531                if(setClientCookies!=null)                              ac.setSetClientCookies(setClientCookies.booleanValue());
532                if(setClientManagement!=null)                   ac.setSetClientManagement(setClientManagement.booleanValue());
533                if(setDomainCookies!=null)                              ac.setSetDomainCookies(setDomainCookies.booleanValue());
534                if(setSessionManagement!=null)                  ac.setSetSessionManagement(setSessionManagement.booleanValue());
535                if(localMode!=-1)                                               ac.setLocalMode(localMode);
536                if(locale!=null)                                                ac.setLocale(locale);
537                if(timeZone!=null)                                              ac.setTimeZone(timeZone);
538                if(webCharset!=null)                                    ac.setWebCharset(webCharset);
539                if(resourceCharset!=null)                               ac.setResourceCharset(resourceCharset);
540                if(sessionType!=-1)                                     ac.setSessionType(sessionType);
541                if(wsType!=-1)                                                  ac.setWSType(wsType);
542                if(triggerDataMember!=null)                     ac.setTriggerComponentDataMember(triggerDataMember.booleanValue());
543                if(compression!=null)                                   ac.setAllowCompression(compression.booleanValue());
544                if(cacheFunction!=null)                                 ac.setDefaultCacheName(Config.CACHE_DEFAULT_FUNCTION, cacheFunction);
545                if(cacheObject!=null)                                   ac.setDefaultCacheName(Config.CACHE_DEFAULT_OBJECT, cacheObject);
546                if(cacheQuery!=null)                                    ac.setDefaultCacheName(Config.CACHE_DEFAULT_QUERY, cacheQuery);
547                if(cacheResource!=null)                                 ac.setDefaultCacheName(Config.CACHE_DEFAULT_RESOURCE, cacheResource);
548                if(cacheTemplate!=null)                                 ac.setDefaultCacheName(Config.CACHE_DEFAULT_TEMPLATE, cacheTemplate);
549                if(cacheInclude!=null)                          ac.setDefaultCacheName(Config.CACHE_DEFAULT_INCLUDE, cacheInclude);
550                if(tag!=null) ac.setTagAttributeDefaultValues(tag);
551                ac.setClientCluster(clientCluster);
552                ac.setSessionCluster(sessionCluster);
553                ac.setCGIScopeReadonly(cgiReadOnly);
554                if(s3!=null)                                                    ac.setS3(AppListenerUtil.toS3(s3));
555                
556                // Scope cascading
557                if(scopeCascading!=-1) ac.setScopeCascading(scopeCascading);
558                
559                // ORM
560                boolean initORM=false;
561                if(!update) {
562                        if(ormenabled==null)ormenabled=false;
563                        if(ormsettings==null)ormsettings=new StructImpl();
564                }
565                if(ormenabled!=null)ac.setORMEnabled(ormenabled);
566                if(ac.isORMEnabled()) {
567                        initORM=true;
568                        if(ormsettings!=null)AppListenerUtil.setORMConfiguration(pageContext, ac, ormsettings);
569                }
570                
571                
572                return initORM;
573        }
574
575        @Override
576        public int doEndTag()   {
577                return EVAL_PAGE;
578        }
579
580}