KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jasper > compiler > JspRuntimeContext


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.compiler;
19
20 import java.io.File JavaDoc;
21 import java.io.FileNotFoundException JavaDoc;
22 import java.io.FilePermission JavaDoc;
23 import java.net.URL JavaDoc;
24 import java.net.URLClassLoader JavaDoc;
25 import java.security.CodeSource JavaDoc;
26 import java.security.PermissionCollection JavaDoc;
27 import java.security.Policy JavaDoc;
28 import java.security.cert.Certificate JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.util.concurrent.ConcurrentHashMap JavaDoc;
32
33 import javax.servlet.ServletContext JavaDoc;
34 import javax.servlet.jsp.JspFactory JavaDoc;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.apache.jasper.Constants;
39 import org.apache.jasper.JspCompilationContext;
40 import org.apache.jasper.Options;
41 import org.apache.jasper.runtime.JspFactoryImpl;
42 import org.apache.jasper.security.SecurityClassLoad;
43 import org.apache.jasper.servlet.JspServletWrapper;
44
45 /**
46  * Class for tracking JSP compile time file dependencies when the
47  * &060;%@include file="..."%&062; directive is used.
48  *
49  * A background thread periodically checks the files a JSP page
50  * is dependent upon. If a dpendent file changes the JSP page
51  * which included it is recompiled.
52  *
53  * Only used if a web application context is a directory.
54  *
55  * @author Glenn L. Nielsen
56  * @version $Revision: 467222 $
57  */

58 public final class JspRuntimeContext {
59
60     // Logger
61
private Log log = LogFactory.getLog(JspRuntimeContext.class);
62
63     /*
64      * Counts how many times the webapp's JSPs have been reloaded.
65      */

66     private int jspReloadCount;
67
68     /**
69      * Preload classes required at runtime by a JSP servlet so that
70      * we don't get a defineClassInPackage security exception.
71      */

72     static {
73         JspFactoryImpl factory = new JspFactoryImpl();
74         SecurityClassLoad.securityClassLoad(factory.getClass().getClassLoader());
75         JspFactory.setDefaultFactory(factory);
76     }
77
78     // ----------------------------------------------------------- Constructors
79

80     /**
81      * Create a JspRuntimeContext for a web application context.
82      *
83      * Loads in any previously generated dependencies from file.
84      *
85      * @param context ServletContext for web application
86      */

87     public JspRuntimeContext(ServletContext JavaDoc context, Options options) {
88
89         this.context = context;
90         this.options = options;
91
92         // Get the parent class loader
93
parentClassLoader =
94             (URLClassLoader JavaDoc) Thread.currentThread().getContextClassLoader();
95         if (parentClassLoader == null) {
96             parentClassLoader =
97                 (URLClassLoader JavaDoc)this.getClass().getClassLoader();
98         }
99
100     if (log.isDebugEnabled()) {
101         if (parentClassLoader != null) {
102         log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is",
103                            parentClassLoader.toString()));
104         } else {
105         log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is",
106                            "<none>"));
107         }
108         }
109
110         initClassPath();
111
112     if (context instanceof org.apache.jasper.servlet.JspCServletContext) {
113         return;
114     }
115
116         if (System.getSecurityManager() != null) {
117             initSecurity();
118         }
119
120         // If this web application context is running from a
121
// directory, start the background compilation thread
122
String JavaDoc appBase = context.getRealPath("/");
123         if (!options.getDevelopment()
124                 && appBase != null
125                 && options.getCheckInterval() > 0) {
126             lastCheck = System.currentTimeMillis();
127         }
128     }
129
130     // ----------------------------------------------------- Instance Variables
131

132     /**
133      * This web applications ServletContext
134      */

135     private ServletContext JavaDoc context;
136     private Options options;
137     private URLClassLoader JavaDoc parentClassLoader;
138     private PermissionCollection JavaDoc permissionCollection;
139     private CodeSource JavaDoc codeSource;
140     private String JavaDoc classpath;
141     private long lastCheck = -1L;
142
143     /**
144      * Maps JSP pages to their JspServletWrapper's
145      */

146     private Map JavaDoc<String JavaDoc, JspServletWrapper> jsps = new ConcurrentHashMap JavaDoc<String JavaDoc, JspServletWrapper>();
147  
148
149     // ------------------------------------------------------ Public Methods
150

151     /**
152      * Add a new JspServletWrapper.
153      *
154      * @param jspUri JSP URI
155      * @param jsw Servlet wrapper for JSP
156      */

157     public void addWrapper(String JavaDoc jspUri, JspServletWrapper jsw) {
158         jsps.put(jspUri, jsw);
159     }
160
161     /**
162      * Get an already existing JspServletWrapper.
163      *
164      * @param jspUri JSP URI
165      * @return JspServletWrapper for JSP
166      */

167     public JspServletWrapper getWrapper(String JavaDoc jspUri) {
168         return jsps.get(jspUri);
169     }
170
171     /**
172      * Remove a JspServletWrapper.
173      *
174      * @param jspUri JSP URI of JspServletWrapper to remove
175      */

176     public void removeWrapper(String JavaDoc jspUri) {
177         jsps.remove(jspUri);
178     }
179
180     /**
181      * Returns the number of JSPs for which JspServletWrappers exist, i.e.,
182      * the number of JSPs that have been loaded into the webapp.
183      *
184      * @return The number of JSPs that have been loaded into the webapp
185      */

186     public int getJspCount() {
187         return jsps.size();
188     }
189
190     /**
191      * Get the SecurityManager Policy CodeSource for this web
192      * applicaiton context.
193      *
194      * @return CodeSource for JSP
195      */

196     public CodeSource JavaDoc getCodeSource() {
197         return codeSource;
198     }
199
200     /**
201      * Get the parent URLClassLoader.
202      *
203      * @return URLClassLoader parent
204      */

205     public URLClassLoader JavaDoc getParentClassLoader() {
206         return parentClassLoader;
207     }
208
209     /**
210      * Get the SecurityManager PermissionCollection for this
211      * web application context.
212      *
213      * @return PermissionCollection permissions
214      */

215     public PermissionCollection JavaDoc getPermissionCollection() {
216         return permissionCollection;
217     }
218
219     /**
220      * Process a "destory" event for this web application context.
221      */

222     public void destroy() {
223         Iterator JavaDoc servlets = jsps.values().iterator();
224         while (servlets.hasNext()) {
225             ((JspServletWrapper) servlets.next()).destroy();
226         }
227     }
228
229     /**
230      * Increments the JSP reload counter.
231      */

232     public synchronized void incrementJspReloadCount() {
233         jspReloadCount++;
234     }
235
236     /**
237      * Resets the JSP reload counter.
238      *
239      * @param count Value to which to reset the JSP reload counter
240      */

241     public synchronized void setJspReloadCount(int count) {
242         this.jspReloadCount = count;
243     }
244
245     /**
246      * Gets the current value of the JSP reload counter.
247      *
248      * @return The current value of the JSP reload counter
249      */

250     public int getJspReloadCount() {
251         return jspReloadCount;
252     }
253
254
255     /**
256      * Method used by background thread to check the JSP dependencies
257      * registered with this class for JSP's.
258      */

259     public void checkCompile() {
260
261         if (lastCheck < 0) {
262             // Checking was disabled
263
return;
264         }
265         long now = System.currentTimeMillis();
266         if (now > (lastCheck + (options.getCheckInterval() * 1000L))) {
267             lastCheck = now;
268         } else {
269             return;
270         }
271         
272         Object JavaDoc [] wrappers = jsps.values().toArray();
273         for (int i = 0; i < wrappers.length; i++ ) {
274             JspServletWrapper jsw = (JspServletWrapper)wrappers[i];
275             JspCompilationContext ctxt = jsw.getJspEngineContext();
276             // JspServletWrapper also synchronizes on this when
277
// it detects it has to do a reload
278
synchronized(jsw) {
279                 try {
280                     ctxt.compile();
281                 } catch (FileNotFoundException JavaDoc ex) {
282                     ctxt.incrementRemoved();
283                 } catch (Throwable JavaDoc t) {
284                     jsw.getServletContext().log("Background compile failed",
285                         t);
286                 }
287             }
288         }
289
290     }
291
292     /**
293      * The classpath that is passed off to the Java compiler.
294      */

295     public String JavaDoc getClassPath() {
296         return classpath;
297     }
298
299
300     // -------------------------------------------------------- Private Methods
301

302
303     /**
304      * Method used to initialize classpath for compiles.
305      */

306     private void initClassPath() {
307
308         URL JavaDoc [] urls = parentClassLoader.getURLs();
309         StringBuffer JavaDoc cpath = new StringBuffer JavaDoc();
310         String JavaDoc sep = System.getProperty("path.separator");
311
312         for(int i = 0; i < urls.length; i++) {
313             // Tomcat 4 can use URL's other than file URL's,
314
// a protocol other than file: will generate a
315
// bad file system path, so only add file:
316
// protocol URL's to the classpath.
317

318             if( urls[i].getProtocol().equals("file") ) {
319                 cpath.append((String JavaDoc)urls[i].getFile()+sep);
320             }
321         }
322
323     cpath.append(options.getScratchDir() + sep);
324
325         String JavaDoc cp = (String JavaDoc) context.getAttribute(Constants.SERVLET_CLASSPATH);
326         if (cp == null || cp.equals("")) {
327             cp = options.getClassPath();
328         }
329
330         classpath = cpath.toString() + cp;
331
332         if(log.isDebugEnabled()) {
333             log.debug("Compilation classpath initialized: " + getClassPath());
334         }
335     }
336
337     /**
338      * Method used to initialize SecurityManager data.
339      */

340     private void initSecurity() {
341
342         // Setup the PermissionCollection for this web app context
343
// based on the permissions configured for the root of the
344
// web app context directory, then add a file read permission
345
// for that directory.
346
Policy JavaDoc policy = Policy.getPolicy();
347         if( policy != null ) {
348             try {
349                 // Get the permissions for the web app context
350
String JavaDoc docBase = context.getRealPath("/");
351                 if( docBase == null ) {
352                     docBase = options.getScratchDir().toString();
353                 }
354                 String JavaDoc codeBase = docBase;
355                 if (!codeBase.endsWith(File.separator)){
356                     codeBase = codeBase + File.separator;
357                 }
358                 File JavaDoc contextDir = new File JavaDoc(codeBase);
359                 URL JavaDoc url = contextDir.getCanonicalFile().toURL();
360                 codeSource = new CodeSource JavaDoc(url,(Certificate JavaDoc[])null);
361                 permissionCollection = policy.getPermissions(codeSource);
362
363                 // Create a file read permission for web app context directory
364
if (!docBase.endsWith(File.separator)){
365                     permissionCollection.add
366                         (new FilePermission JavaDoc(docBase,"read"));
367                     docBase = docBase + File.separator;
368                 } else {
369                     permissionCollection.add
370                         (new FilePermission JavaDoc
371                             (docBase.substring(0,docBase.length() - 1),"read"));
372                 }
373                 docBase = docBase + "-";
374                 permissionCollection.add(new FilePermission JavaDoc(docBase,"read"));
375
376                 // Create a file read permission for web app tempdir (work)
377
// directory
378
String JavaDoc workDir = options.getScratchDir().toString();
379                 if (!workDir.endsWith(File.separator)){
380                     permissionCollection.add
381                         (new FilePermission JavaDoc(workDir,"read"));
382                     workDir = workDir + File.separator;
383                 }
384                 workDir = workDir + "-";
385                 permissionCollection.add(new FilePermission JavaDoc(workDir,"read"));
386
387                 // Allow the JSP to access org.apache.jasper.runtime.HttpJspBase
388
permissionCollection.add( new RuntimePermission JavaDoc(
389                     "accessClassInPackage.org.apache.jasper.runtime") );
390
391                 if (parentClassLoader instanceof URLClassLoader JavaDoc) {
392                     URL JavaDoc [] urls = parentClassLoader.getURLs();
393                     String JavaDoc jarUrl = null;
394                     String JavaDoc jndiUrl = null;
395                     for (int i=0; i<urls.length; i++) {
396                         if (jndiUrl == null
397                                 && urls[i].toString().startsWith("jndi:") ) {
398                             jndiUrl = urls[i].toString() + "-";
399                         }
400                         if (jarUrl == null
401                                 && urls[i].toString().startsWith("jar:jndi:")
402                                 ) {
403                             jarUrl = urls[i].toString();
404                             jarUrl = jarUrl.substring(0,jarUrl.length() - 2);
405                             jarUrl = jarUrl.substring(0,
406                                      jarUrl.lastIndexOf('/')) + "/-";
407                         }
408                     }
409                     if (jarUrl != null) {
410                         permissionCollection.add(
411                                 new FilePermission JavaDoc(jarUrl,"read"));
412                         permissionCollection.add(
413                                 new FilePermission JavaDoc(jarUrl.substring(4),"read"));
414                     }
415                     if (jndiUrl != null)
416                         permissionCollection.add(
417                                 new FilePermission JavaDoc(jndiUrl,"read") );
418                 }
419             } catch(Exception JavaDoc e) {
420                 context.log("Security Init for context failed",e);
421             }
422         }
423     }
424
425
426 }
427
Popular Tags