1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.jasper;
19
20 import java.io.File;
21 import java.util.Enumeration;
22 import java.util.Map;
23 import java.util.Properties;
24
25 import javax.servlet.ServletConfig;
26 import javax.servlet.ServletContext;
27 import javax.servlet.jsp.tagext.TagLibraryInfo;
28
29 import org.apache.jasper.compiler.JspConfig;
30 import org.apache.jasper.compiler.Localizer;
31 import org.apache.jasper.compiler.TagPluginManager;
32 import org.apache.jasper.compiler.TldCache;
33 import org.apache.juli.logging.Log;
34 import org.apache.juli.logging.LogFactory;
35
36 /**
37  * A class to hold all init parameters specific to the JSP engine.
38  *
39  * @author Anil K. Vijendran
40  * @author Hans Bergsten
41  * @author Pierre Delisle
42  */

43 public final class EmbeddedServletOptions implements Options {
44
45     // Logger
46     private final Log log = LogFactory.getLog(EmbeddedServletOptions.class); // must not be static
47
48     private Properties settings = new Properties();
49
50     /**
51      * Is Jasper being used in development mode?
52      */

53     private boolean development = true;
54
55     /**
56      * Should Ant fork its java compiles of JSP pages.
57      */

58     public boolean fork = true;
59
60     /**
61      * Do you want to keep the generated Java files around?
62      */

63     private boolean keepGenerated = true;
64
65     /**
66      * How should template text that consists entirely of whitespace be handled?
67      */

68     private TrimSpacesOption trimSpaces = TrimSpacesOption.FALSE;
69
70     /**
71      * Determines whether tag handler pooling is enabled.
72      */

73     private boolean isPoolingEnabled = true;
74
75     /**
76      * Do you want support for "mapped" files? This will generate
77      * servlet that has a print statement per line of the JSP file.
78      * This seems like a really nice feature to have for debugging.
79      */

80     private boolean mappedFile = true;
81
82     /**
83      * Do we want to include debugging information in the class file?
84      */

85     private boolean classDebugInfo = true;
86
87     /**
88      * Background compile thread check interval in seconds.
89      */

90     private int checkInterval = 0;
91
92     /**
93      * Is the generation of SMAP info for JSR45 debugging suppressed?
94      */

95     private boolean isSmapSuppressed = false;
96
97     /**
98      * Should SMAP info for JSR45 debugging be dumped to a file?
99      */

100     private boolean isSmapDumped = false;
101
102     /**
103      * Are Text strings to be generated as char arrays?
104      */

105     private boolean genStringAsCharArray = false;
106
107     private boolean errorOnUseBeanInvalidClassAttribute = true;
108
109     /**
110      * I want to see my generated servlets. Which directory are they
111      * in?
112      */

113     private File scratchDir;
114
115     /**
116      * Need to have this as is for versions 4 and 5 of IE. Can be set from
117      * the initParams so if it changes in the future all that is needed is
118      * to have a jsp initParam of type ieClassId="<value>"
119      */

120     private String ieClassId = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
121
122     /**
123      * What classpath should I use while compiling generated servlets?
124      */

125     private String classpath = null;
126
127     /**
128      * Compiler to use.
129      */

130     private String compiler = null;
131
132     /**
133      * Compiler target VM.
134      */

135     private String compilerTargetVM = "1.8";
136
137     /**
138      * The compiler source VM.
139      */

140     private String compilerSourceVM = "1.8";
141
142     /**
143      * The compiler class name.
144      */

145     private String compilerClassName = null;
146
147     /**
148      * Cache for the TLD URIs, resource paths and parsed files.
149      */

150     private TldCache tldCache = null;
151
152     /**
153      * Jsp config information
154      */

155     private JspConfig jspConfig = null;
156
157     /**
158      * TagPluginManager
159      */

160     private TagPluginManager tagPluginManager = null;
161
162     /**
163      * Java platform encoding to generate the JSP
164      * page servlet.
165      */

166     private String javaEncoding = "UTF-8";
167
168     /**
169      * Modification test interval.
170      */

171     private int modificationTestInterval = 4;
172
173     /**
174      * Is re-compilation attempted immediately after a failure?
175      */

176     private boolean recompileOnFail = false;
177
178     /**
179      * Is generation of X-Powered-By response header enabled/disabled?
180      */

181     private boolean xpoweredBy;
182
183     /**
184      * Should we include a source fragment in exception messages, which could be displayed
185      * to the developer ?
186      */

187     private boolean displaySourceFragment = true;
188
189
190     /**
191      * The maximum number of loaded jsps per web-application. If there are more
192      * jsps loaded, they will be unloaded.
193      */

194     private int maxLoadedJsps = -1;
195
196     /**
197      * The idle time in seconds after which a JSP is unloaded.
198      * If unset or less or equal than 0, no jsps are unloaded.
199      */

200     private int jspIdleTimeout = -1;
201
202     /**
203      * Should JSP.1.6 be applied strictly to attributes defined using scriptlet
204      * expressions?
205      */

206     private boolean strictQuoteEscaping = true;
207
208     /**
209      * When EL is used in JSP attribute values, should the rules for quoting of
210      * attributes described in JSP.1.6 be applied to the expression?
211      */

212     private boolean quoteAttributeEL = true;
213
214     public String getProperty(String name ) {
215         return settings.getProperty( name );
216     }
217
218     public void setProperty(String name, String value ) {
219         if (name != null && value != null){
220             settings.setProperty( name, value );
221         }
222     }
223
224     public void setQuoteAttributeEL(boolean b) {
225         this.quoteAttributeEL = b;
226     }
227
228     @Override
229     public boolean getQuoteAttributeEL() {
230         return quoteAttributeEL;
231     }
232
233     /**
234      * Are we keeping generated code around?
235      */

236     @Override
237     public boolean getKeepGenerated() {
238         return keepGenerated;
239     }
240
241     @Override
242     public TrimSpacesOption getTrimSpaces() {
243         return trimSpaces;
244     }
245
246     @Override
247     public boolean isPoolingEnabled() {
248         return isPoolingEnabled;
249     }
250
251     /**
252      * Are we supporting HTML mapped servlets?
253      */

254     @Override
255     public boolean getMappedFile() {
256         return mappedFile;
257     }
258
259     /**
260      * Should class files be compiled with debug information?
261      */

262     @Override
263     public boolean getClassDebugInfo() {
264         return classDebugInfo;
265     }
266
267     /**
268      * Background JSP compile thread check interval
269      */

270     @Override
271     public int getCheckInterval() {
272         return checkInterval;
273     }
274
275     /**
276      * Modification test interval.
277      */

278     @Override
279     public int getModificationTestInterval() {
280         return modificationTestInterval;
281     }
282
283     /**
284      * Re-compile on failure.
285      */

286     @Override
287     public boolean getRecompileOnFail() {
288         return recompileOnFail;
289     }
290
291     /**
292      * Is Jasper being used in development mode?
293      */

294     @Override
295     public boolean getDevelopment() {
296         return development;
297     }
298
299     /**
300      * Is the generation of SMAP info for JSR45 debugging suppressed?
301      */

302     @Override
303     public boolean isSmapSuppressed() {
304         return isSmapSuppressed;
305     }
306
307     /**
308      * Should SMAP info for JSR45 debugging be dumped to a file?
309      */

310     @Override
311     public boolean isSmapDumped() {
312         return isSmapDumped;
313     }
314
315     /**
316      * Are Text strings to be generated as char arrays?
317      */

318     @Override
319     public boolean genStringAsCharArray() {
320         return this.genStringAsCharArray;
321     }
322
323     /**
324      * Class ID for use in the plugin tag when the browser is IE.
325      */

326     @Override
327     public String getIeClassId() {
328         return ieClassId;
329     }
330
331     /**
332      * What is my scratch dir?
333      */

334     @Override
335     public File getScratchDir() {
336         return scratchDir;
337     }
338
339     /**
340      * What classpath should I use while compiling the servlets
341      * generated from JSP files?
342      */

343     @Override
344     public String getClassPath() {
345         return classpath;
346     }
347
348     /**
349      * Is generation of X-Powered-By response header enabled/disabled?
350      */

351     @Override
352     public boolean isXpoweredBy() {
353         return xpoweredBy;
354     }
355
356     /**
357      * Compiler to use.
358      */

359     @Override
360     public String getCompiler() {
361         return compiler;
362     }
363
364     /**
365      * @see Options#getCompilerTargetVM
366      */

367     @Override
368     public String getCompilerTargetVM() {
369         return compilerTargetVM;
370     }
371
372     /**
373      * @see Options#getCompilerSourceVM
374      */

375     @Override
376     public String getCompilerSourceVM() {
377         return compilerSourceVM;
378     }
379
380     /**
381      * Java compiler class to use.
382      */

383     @Override
384     public String getCompilerClassName() {
385         return compilerClassName;
386     }
387
388     @Override
389     public boolean getErrorOnUseBeanInvalidClassAttribute() {
390         return errorOnUseBeanInvalidClassAttribute;
391     }
392
393     public void setErrorOnUseBeanInvalidClassAttribute(boolean b) {
394         errorOnUseBeanInvalidClassAttribute = b;
395     }
396
397     @Override
398     public TldCache getTldCache() {
399         return tldCache;
400     }
401
402     public void setTldCache(TldCache tldCache) {
403         this.tldCache = tldCache;
404     }
405
406     @Override
407     public String getJavaEncoding() {
408         return javaEncoding;
409     }
410
411     @Override
412     public boolean getFork() {
413         return fork;
414     }
415
416     @Override
417     public JspConfig getJspConfig() {
418         return jspConfig;
419     }
420
421     @Override
422     public TagPluginManager getTagPluginManager() {
423         return tagPluginManager;
424     }
425
426     @Override
427     public boolean isCaching() {
428         return false;
429     }
430
431     @Override
432     public Map<String, TagLibraryInfo> getCache() {
433         return null;
434     }
435
436     /**
437      * Should we include a source fragment in exception messages, which could be displayed
438      * to the developer ?
439      */

440     @Override
441     public boolean getDisplaySourceFragment() {
442         return displaySourceFragment;
443     }
444
445     /**
446      * Should jsps be unloaded if to many are loaded?
447      * If set to a value greater than 0 eviction of jsps is started. Default: -1
448      */

449     @Override
450     public int getMaxLoadedJsps() {
451         return maxLoadedJsps;
452     }
453
454     /**
455      * Should any jsps be unloaded when being idle for this time in seconds?
456      * If set to a value greater than 0 eviction of jsps is started. Default: -1
457      */

458     @Override
459     public int getJspIdleTimeout() {
460         return jspIdleTimeout;
461     }
462
463     @Override
464     public boolean getStrictQuoteEscaping() {
465         return strictQuoteEscaping;
466     }
467
468     /**
469      * Create an EmbeddedServletOptions object using data available from
470      * ServletConfig and ServletContext.
471      * @param config The Servlet config
472      * @param context The Servlet context
473      */

474     public EmbeddedServletOptions(ServletConfig config, ServletContext context) {
475
476         Enumeration<String> enumeration=config.getInitParameterNames();
477         while( enumeration.hasMoreElements() ) {
478             String k=enumeration.nextElement();
479             String v=config.getInitParameter( k );
480             setProperty( k, v);
481         }
482
483         String keepgen = config.getInitParameter("keepgenerated");
484         if (keepgen != null) {
485             if (keepgen.equalsIgnoreCase("true")) {
486                 this.keepGenerated = true;
487             } else if (keepgen.equalsIgnoreCase("false")) {
488                 this.keepGenerated = false;
489             } else {
490                 if (log.isWarnEnabled()) {
491                     log.warn(Localizer.getMessage("jsp.warning.keepgen"));
492                 }
493             }
494         }
495
496
497         String trimsp = config.getInitParameter("trimSpaces");
498         if (trimsp != null) {
499             try {
500                 trimSpaces = TrimSpacesOption.valueOf(trimsp.toUpperCase());
501             } catch (IllegalArgumentException iae) {
502                 if (log.isWarnEnabled()) {
503                     log.warn(Localizer.getMessage("jsp.warning.trimspaces"), iae);
504                 }
505             }
506         }
507
508         this.isPoolingEnabled = true;
509         String poolingEnabledParam = config.getInitParameter("enablePooling");
510         if (poolingEnabledParam != null
511                 && !poolingEnabledParam.equalsIgnoreCase("true")) {
512             if (poolingEnabledParam.equalsIgnoreCase("false")) {
513                 this.isPoolingEnabled = false;
514             } else {
515                 if (log.isWarnEnabled()) {
516                     log.warn(Localizer.getMessage("jsp.warning.enablePooling"));
517                 }
518             }
519         }
520
521         String mapFile = config.getInitParameter("mappedfile");
522         if (mapFile != null) {
523             if (mapFile.equalsIgnoreCase("true")) {
524                 this.mappedFile = true;
525             } else if (mapFile.equalsIgnoreCase("false")) {
526                 this.mappedFile = false;
527             } else {
528                 if (log.isWarnEnabled()) {
529                     log.warn(Localizer.getMessage("jsp.warning.mappedFile"));
530                 }
531             }
532         }
533
534         String debugInfo = config.getInitParameter("classdebuginfo");
535         if (debugInfo != null) {
536             if (debugInfo.equalsIgnoreCase("true")) {
537                 this.classDebugInfo  = true;
538             } else if (debugInfo.equalsIgnoreCase("false")) {
539                 this.classDebugInfo  = false;
540             } else {
541                 if (log.isWarnEnabled()) {
542                     log.warn(Localizer.getMessage("jsp.warning.classDebugInfo"));
543                 }
544             }
545         }
546
547         String checkInterval = config.getInitParameter("checkInterval");
548         if (checkInterval != null) {
549             try {
550                 this.checkInterval = Integer.parseInt(checkInterval);
551             } catch(NumberFormatException ex) {
552                 if (log.isWarnEnabled()) {
553                     log.warn(Localizer.getMessage("jsp.warning.checkInterval"));
554                 }
555             }
556         }
557
558         String modificationTestInterval = config.getInitParameter("modificationTestInterval");
559         if (modificationTestInterval != null) {
560             try {
561                 this.modificationTestInterval = Integer.parseInt(modificationTestInterval);
562             } catch(NumberFormatException ex) {
563                 if (log.isWarnEnabled()) {
564                     log.warn(Localizer.getMessage("jsp.warning.modificationTestInterval"));
565                 }
566             }
567         }
568
569         String recompileOnFail = config.getInitParameter("recompileOnFail");
570         if (recompileOnFail != null) {
571             if (recompileOnFail.equalsIgnoreCase("true")) {
572                 this.recompileOnFail = true;
573             } else if (recompileOnFail.equalsIgnoreCase("false")) {
574                 this.recompileOnFail = false;
575             } else {
576                 if (log.isWarnEnabled()) {
577                     log.warn(Localizer.getMessage("jsp.warning.recompileOnFail"));
578                 }
579             }
580         }
581         String development = config.getInitParameter("development");
582         if (development != null) {
583             if (development.equalsIgnoreCase("true")) {
584                 this.development = true;
585             } else if (development.equalsIgnoreCase("false")) {
586                 this.development = false;
587             } else {
588                 if (log.isWarnEnabled()) {
589                     log.warn(Localizer.getMessage("jsp.warning.development"));
590                 }
591             }
592         }
593
594         String suppressSmap = config.getInitParameter("suppressSmap");
595         if (suppressSmap != null) {
596             if (suppressSmap.equalsIgnoreCase("true")) {
597                 isSmapSuppressed = true;
598             } else if (suppressSmap.equalsIgnoreCase("false")) {
599                 isSmapSuppressed = false;
600             } else {
601                 if (log.isWarnEnabled()) {
602                     log.warn(Localizer.getMessage("jsp.warning.suppressSmap"));
603                 }
604             }
605         }
606
607         String dumpSmap = config.getInitParameter("dumpSmap");
608         if (dumpSmap != null) {
609             if (dumpSmap.equalsIgnoreCase("true")) {
610                 isSmapDumped = true;
611             } else if (dumpSmap.equalsIgnoreCase("false")) {
612                 isSmapDumped = false;
613             } else {
614                 if (log.isWarnEnabled()) {
615                     log.warn(Localizer.getMessage("jsp.warning.dumpSmap"));
616                 }
617             }
618         }
619
620         String genCharArray = config.getInitParameter("genStringAsCharArray");
621         if (genCharArray != null) {
622             if (genCharArray.equalsIgnoreCase("true")) {
623                 genStringAsCharArray = true;
624             } else if (genCharArray.equalsIgnoreCase("false")) {
625                 genStringAsCharArray = false;
626             } else {
627                 if (log.isWarnEnabled()) {
628                     log.warn(Localizer.getMessage("jsp.warning.genchararray"));
629                 }
630             }
631         }
632
633         String errBeanClass = config.getInitParameter("errorOnUseBeanInvalidClassAttribute");
634         if (errBeanClass != null) {
635             if (errBeanClass.equalsIgnoreCase("true")) {
636                 errorOnUseBeanInvalidClassAttribute = true;
637             } else if (errBeanClass.equalsIgnoreCase("false")) {
638                 errorOnUseBeanInvalidClassAttribute = false;
639             } else {
640                 if (log.isWarnEnabled()) {
641                     log.warn(Localizer.getMessage("jsp.warning.errBean"));
642                 }
643             }
644         }
645
646         String ieClassId = config.getInitParameter("ieClassId");
647         if (ieClassId != null)
648             this.ieClassId = ieClassId;
649
650         String classpath = config.getInitParameter("classpath");
651         if (classpath != null)
652             this.classpath = classpath;
653
654         /*
655          * scratchdir
656          */

657         String dir = config.getInitParameter("scratchdir");
658         if (dir != null && Constants.IS_SECURITY_ENABLED) {
659             log.info(Localizer.getMessage("jsp.info.ignoreSetting""scratchdir", dir));
660             dir = null;
661         }
662         if (dir != null) {
663             scratchDir = new File(dir);
664         } else {
665             // First try the Servlet 2.2 javax.servlet.context.tempdir property
666             scratchDir = (File) context.getAttribute(ServletContext.TEMPDIR);
667             if (scratchDir == null) {
668                 // Not running in a Servlet 2.2 container.
669                 // Try to get the JDK 1.2 java.io.tmpdir property
670                 dir = System.getProperty("java.io.tmpdir");
671                 if (dir != null)
672                     scratchDir = new File(dir);
673             }
674         }
675         if (this.scratchDir == null) {
676             log.fatal(Localizer.getMessage("jsp.error.no.scratch.dir"));
677             return;
678         }
679
680         if (!(scratchDir.exists() && scratchDir.canRead() &&
681                 scratchDir.canWrite() && scratchDir.isDirectory()))
682             log.fatal(Localizer.getMessage("jsp.error.bad.scratch.dir",
683                     scratchDir.getAbsolutePath()));
684
685         this.compiler = config.getInitParameter("compiler");
686
687         String compilerTargetVM = config.getInitParameter("compilerTargetVM");
688         if(compilerTargetVM != null) {
689             this.compilerTargetVM = compilerTargetVM;
690         }
691
692         String compilerSourceVM = config.getInitParameter("compilerSourceVM");
693         if(compilerSourceVM != null) {
694             this.compilerSourceVM = compilerSourceVM;
695         }
696
697         String javaEncoding = config.getInitParameter("javaEncoding");
698         if (javaEncoding != null) {
699             this.javaEncoding = javaEncoding;
700         }
701
702         String compilerClassName = config.getInitParameter("compilerClassName");
703         if (compilerClassName != null) {
704             this.compilerClassName = compilerClassName;
705         }
706
707         String fork = config.getInitParameter("fork");
708         if (fork != null) {
709             if (fork.equalsIgnoreCase("true")) {
710                 this.fork = true;
711             } else if (fork.equalsIgnoreCase("false")) {
712                 this.fork = false;
713             } else {
714                 if (log.isWarnEnabled()) {
715                     log.warn(Localizer.getMessage("jsp.warning.fork"));
716                 }
717             }
718         }
719
720         String xpoweredBy = config.getInitParameter("xpoweredBy");
721         if (xpoweredBy != null) {
722             if (xpoweredBy.equalsIgnoreCase("true")) {
723                 this.xpoweredBy = true;
724             } else if (xpoweredBy.equalsIgnoreCase("false")) {
725                 this.xpoweredBy = false;
726             } else {
727                 if (log.isWarnEnabled()) {
728                     log.warn(Localizer.getMessage("jsp.warning.xpoweredBy"));
729                 }
730             }
731         }
732
733         String displaySourceFragment = config.getInitParameter("displaySourceFragment");
734         if (displaySourceFragment != null) {
735             if (displaySourceFragment.equalsIgnoreCase("true")) {
736                 this.displaySourceFragment = true;
737             } else if (displaySourceFragment.equalsIgnoreCase("false")) {
738                 this.displaySourceFragment = false;
739             } else {
740                 if (log.isWarnEnabled()) {
741                     log.warn(Localizer.getMessage("jsp.warning.displaySourceFragment"));
742                 }
743             }
744         }
745
746         String maxLoadedJsps = config.getInitParameter("maxLoadedJsps");
747         if (maxLoadedJsps != null) {
748             try {
749                 this.maxLoadedJsps = Integer.parseInt(maxLoadedJsps);
750             } catch(NumberFormatException ex) {
751                 if (log.isWarnEnabled()) {
752                     log.warn(Localizer.getMessage("jsp.warning.maxLoadedJsps"""+this.maxLoadedJsps));
753                 }
754             }
755         }
756
757         String jspIdleTimeout = config.getInitParameter("jspIdleTimeout");
758         if (jspIdleTimeout != null) {
759             try {
760                 this.jspIdleTimeout = Integer.parseInt(jspIdleTimeout);
761             } catch(NumberFormatException ex) {
762                 if (log.isWarnEnabled()) {
763                     log.warn(Localizer.getMessage("jsp.warning.jspIdleTimeout"""+this.jspIdleTimeout));
764                 }
765             }
766         }
767
768         String strictQuoteEscaping = config.getInitParameter("strictQuoteEscaping");
769         if (strictQuoteEscaping != null) {
770             if (strictQuoteEscaping.equalsIgnoreCase("true")) {
771                 this.strictQuoteEscaping = true;
772             } else if (strictQuoteEscaping.equalsIgnoreCase("false")) {
773                 this.strictQuoteEscaping = false;
774             } else {
775                 if (log.isWarnEnabled()) {
776                     log.warn(Localizer.getMessage("jsp.warning.strictQuoteEscaping"));
777                 }
778             }
779         }
780
781         String quoteAttributeEL = config.getInitParameter("quoteAttributeEL");
782         if (quoteAttributeEL != null) {
783             if (quoteAttributeEL.equalsIgnoreCase("true")) {
784                 this.quoteAttributeEL = true;
785             } else if (quoteAttributeEL.equalsIgnoreCase("false")) {
786                 this.quoteAttributeEL = false;
787             } else {
788                 if (log.isWarnEnabled()) {
789                     log.warn(Localizer.getMessage("jsp.warning.quoteAttributeEL"));
790                 }
791             }
792         }
793
794         // Setup the global Tag Libraries location cache for this
795         // web-application.
796         tldCache = TldCache.getInstance(context);
797
798         // Setup the jsp config info for this web app.
799         jspConfig = new JspConfig(context);
800
801         // Create a Tag plugin instance
802         tagPluginManager = new TagPluginManager(context);
803     }
804
805 }
806
807