KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > jsp > Page


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.jsp;
31
32 import com.caucho.jsp.cfg.JspPropertyGroup;
33 import com.caucho.loader.Environment;
34 import com.caucho.log.Log;
35 import com.caucho.server.connection.CauchoResponse;
36 import com.caucho.server.connection.ToCharResponseAdapter;
37 import com.caucho.server.webapp.WebApp;
38 import com.caucho.util.Alarm;
39 import com.caucho.util.Base64;
40 import com.caucho.util.CharBuffer;
41 import com.caucho.util.QDate;
42 import com.caucho.vfs.Depend;
43 import com.caucho.vfs.Dependency;
44 import com.caucho.vfs.Path;
45 import com.caucho.vfs.PersistentDependency;
46
47 import javax.servlet.Servlet JavaDoc;
48 import javax.servlet.ServletConfig JavaDoc;
49 import javax.servlet.ServletContext JavaDoc;
50 import javax.servlet.ServletException JavaDoc;
51 import javax.servlet.http.HttpServletRequest JavaDoc;
52 import javax.servlet.http.HttpServletResponse JavaDoc;
53 import java.io.IOException JavaDoc;
54 import java.lang.reflect.Method JavaDoc;
55 import java.util.ArrayList JavaDoc;
56 import java.util.Enumeration JavaDoc;
57 import java.util.HashMap JavaDoc;
58 import java.util.logging.Level JavaDoc;
59 import java.util.logging.Logger JavaDoc;
60
61 /**
62  * Represents a compiled JSP page.
63  */

64 abstract public class Page implements Servlet JavaDoc, ServletConfig JavaDoc, CauchoPage {
65   protected static final Logger JavaDoc _caucho_log = Log.open(Page.class);
66
67   private ServletConfig JavaDoc _config;
68   private WebApp _webApp;
69   
70   private ArrayList JavaDoc<PersistentDependency> _depends;
71   private ArrayList JavaDoc<Depend> _cacheDepends;
72   private String JavaDoc _media;
73   protected String JavaDoc _contentType;
74   protected boolean _alwaysModified;
75   protected boolean _neverModified;
76
77   private PageManager.Entry _entry;
78   private long _lastModified;
79   private String JavaDoc _lastModifiedString;
80   private String JavaDoc _etag;
81   private QDate _calendar;
82   
83   private long _updateInterval = Environment.getDependencyCheckInterval();
84   private long _lastUpdateCheck;
85   private JspManager _jspManager;
86
87   private boolean _isRecompiling = false;
88   private int _useCount;
89   private boolean _isDead = true;
90
91   public void init(Path path)
92     throws ServletException JavaDoc
93   {
94   }
95
96   void _caucho_setContentType(String JavaDoc contentType)
97   {
98     _contentType = contentType;
99   }
100
101   void _caucho_setUpdateInterval(long updateInterval)
102   {
103     _updateInterval = updateInterval;
104   }
105
106   void _caucho_setJspManager(JspManager manager)
107   {
108     _jspManager = manager;
109   }
110
111   void _caucho_unload()
112   {
113     if (_jspManager != null)
114       _jspManager.unload(this);
115   }
116
117   void _caucho_setEntry(PageManager.Entry entry)
118   {
119     _entry = entry;
120   }
121
122   protected void _caucho_setContentType(String JavaDoc contentType, String JavaDoc encoding)
123   {
124     if (encoding != null && encoding.equals("ISO-8859-1"))
125       encoding = null;
126     
127     _contentType = contentType;
128   }
129
130   /**
131    * Marks the page as uncacheable.
132    */

133   void _caucho_setUncacheable()
134   {
135     _cacheDepends = null;
136   }
137
138   /**
139    * When called treats the JSP page as always modified, i.e. always forcing
140    * recompilation.
141    */

142   protected void _caucho_setAlwaysModified()
143   {
144     if (_cacheDepends == null)
145       _alwaysModified = true;
146   }
147
148   /**
149    * When called treats the JSP page as always modified, i.e. always forcing
150    * recompilation.
151    */

152   protected void _caucho_setModified()
153   {
154     _alwaysModified = true;
155   }
156
157   /**
158    * Set if the page is never modified. Some users want to deploy
159    * the JSP classes without the JSP source.
160    */

161   protected void _caucho_setNeverModified(boolean modified)
162   {
163     _neverModified = modified;
164   }
165
166   /**
167    * Adds a dependency to the page.
168    *
169    * @param path the file the JSP page is dependent on.
170    */

171   protected void _caucho_addDepend(Path path)
172   {
173     Depend depend = new Depend(path);
174     depend.setRequireSource(getRequireSource());
175
176     _caucho_addDepend(depend);
177   }
178
179   /**
180    * Adds a dependency to the page.
181    *
182    * @param path the file the JSP page is dependent on.
183    */

184   protected void _caucho_addDepend(PersistentDependency depend)
185   {
186     if (_depends == null)
187       _depends = new ArrayList JavaDoc<PersistentDependency>();
188
189     if (! _depends.contains(depend))
190       _depends.add(depend);
191   }
192
193   /**
194    * Adds an array of dependencies to the page.
195    */

196   protected void _caucho_addDepend(ArrayList JavaDoc<PersistentDependency> dependList)
197   {
198     if (dependList == null)
199       return;
200
201     for (int i = 0; i < dependList.size(); i++)
202       _caucho_addDepend(dependList.get(i));
203   }
204   
205   /**
206    * Adds a JSP source dependency. If the source file changes, the JSP must
207    * be recompiled.
208    *
209    * @param path the path to the file
210    * @param lastModified the last modified time
211    * @param length the length of the file
212    */

213   protected void _caucho_addDepend(Path path,
214                                    long lastModified,
215                                    long length)
216   {
217     if (_depends == null)
218       _depends = new ArrayList JavaDoc<PersistentDependency>();
219
220     Depend depend = new Depend(path, lastModified, length);
221     depend.setRequireSource(getRequireSource());
222
223     _caucho_addDepend(depend);
224   }
225
226   /**
227    * Marks the page as cacheable.
228    */

229   protected void _caucho_setCacheable()
230   {
231     _cacheDepends = new ArrayList JavaDoc<Depend>();
232     _alwaysModified = false;
233   }
234
235
236   /**
237    * Adds a single cache dependency. A cache dependency will cause
238    * the page to be rerun, but will not force a recompilation of the JSP.
239    *
240    * @param path the path to the file
241    * @param lastModified the last modified time
242    * @param length the length of the file
243    */

244   protected void _caucho_addCacheDepend(Path path,
245                                         long lastModified,
246                                         long length)
247   {
248     if (_cacheDepends == null)
249       _cacheDepends = new ArrayList JavaDoc<Depend>();
250     
251     Depend depend = new Depend(path, lastModified, length);
252
253     if (! _cacheDepends.contains(depend))
254       _cacheDepends.add(depend);
255   }
256
257   /**
258    * Adds an array of dependencies which will change the results of
259    * running the page.
260    *
261    * @param depends an array list of Depend
262    */

263   void _caucho_setCacheable(ArrayList JavaDoc<Path> depends)
264   {
265     _cacheDepends = new ArrayList JavaDoc<Depend>();
266     for (int i = 0; i < depends.size(); i++) {
267       Path path = depends.get(i);
268
269       Depend depend = new Depend(path);
270       depend.setRequireSource(getRequireSource());
271
272       if (! _cacheDepends.contains(depend))
273         _cacheDepends.add(depend);
274     }
275   }
276
277   /**
278    * Returns true if the underlying source has been modified.
279    */

280   public boolean _caucho_isModified()
281   {
282     if (_alwaysModified || _isDead)
283       return true;
284     
285     if (_depends == null)
286       return false;
287     
288     for (int i = 0; i < _depends.size(); i++) {
289       Dependency depend = _depends.get(i);
290
291       if (depend.isModified())
292     return true;
293     }
294
295     return false;
296   }
297
298   /***
299    * Returns true if the underlying source has been modified.
300    */

301   public boolean cauchoIsModified()
302   {
303     long now = Alarm.getCurrentTime();
304
305     if (_alwaysModified || _isDead)
306       return true;
307     else if (now < _lastUpdateCheck + _updateInterval)
308       return false;
309
310     /* XXX: this check is redundant, because the invocation has already
311      * checked it.
312     ClassLoader classLoader = getClass().getClassLoader();
313
314     if (classLoader instanceof DynamicClassLoader) {
315       DynamicClassLoader dynLoader;
316       dynLoader = (DynamicClassLoader) getClass().getClassLoader();
317
318       if (dynLoader.isModified())
319         return true;
320     }
321     */

322       
323     if (_neverModified) {
324       _lastUpdateCheck = now;
325
326       if (_depends == null)
327     return false;
328
329       for (int i = 0; i < _depends.size(); i++) {
330     Dependency depend = _depends.get(i);
331     if (depend.isModified())
332       return true;
333       }
334       
335       return false;
336     }
337     else {
338       boolean isModified = _caucho_isModified();
339
340       if (! isModified)
341         _lastUpdateCheck = now;
342       return isModified;
343     }
344   }
345
346   protected HashMap JavaDoc<String JavaDoc,Method JavaDoc> _caucho_getFunctionMap()
347   {
348     return null;
349   }
350   
351   /**
352    * Returns true if deleting the underlying JSP will force a recompilation.
353    */

354   private boolean getRequireSource()
355   {
356     return false;
357   }
358
359   /**
360    * Initialize the servlet.
361    */

362   public void init(ServletConfig JavaDoc config)
363     throws ServletException JavaDoc
364   {
365     if (_config != null)
366       return;
367     
368     _config = config;
369     _isDead = false;
370     
371     _webApp = (WebApp) config.getServletContext();
372
373     cauchoIsModified();
374
375     if (! disableLog() && _caucho_log.isLoggable(Level.FINE))
376       _caucho_log.fine(getClass().getName() + " init");
377   }
378
379   /**
380    * Returns true if initializes.
381    */

382   public boolean isInit()
383   {
384     return _config != null;
385   }
386
387   /**
388    * Returns the Resin webApp.
389    */

390   public WebApp _caucho_getApplication()
391   {
392     return _webApp;
393   }
394
395   public ServletContext JavaDoc getServletContext()
396   {
397     return _webApp;
398   }
399
400   public String JavaDoc getServletName()
401   {
402     return _config.getServletName();
403   }
404
405   public String JavaDoc getInitParameter(String JavaDoc name)
406   {
407     return _config.getInitParameter(name);
408   }
409
410   public Enumeration JavaDoc getInitParameterNames()
411   {
412     return _config.getInitParameterNames();
413   }
414
415   public void log(String JavaDoc msg)
416   {
417     _webApp.log(getClass().getName() + ": " + msg);
418   }
419
420   public void log(String JavaDoc msg, Throwable JavaDoc cause)
421   {
422     _webApp.log(getClass().getName() + ": " + msg, cause);
423   }
424
425   public String JavaDoc getServletInfo()
426   {
427     return "A JSP Page";
428   }
429
430   boolean disableLog()
431   {
432     JspPropertyGroup jsp = _webApp.getJsp();
433
434     if (jsp != null)
435       return jsp.isDisableLog();
436
437     return true;
438   }
439
440   /**
441    * Returns this servlet's configuration.
442    */

443   public ServletConfig JavaDoc getServletConfig()
444   {
445     return _config;
446   }
447
448   /**
449    * Initialize the response headers.
450    */

451   public void _caucho_init(HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc res)
452   {
453     if (_contentType != null)
454       res.setContentType(_contentType);
455     else
456       res.setContentType("text/html");
457   }
458
459   /**
460    * Returns the Last-Modified time for use in caching. If the result
461    * is &lt;= 0, last-modified caching is disabled.
462    *
463    * @return the last modified time.
464    */

465   public long getLastModified(HttpServletRequest JavaDoc request)
466   {
467     return _caucho_lastModified();
468   }
469
470   /**
471    * The default Last-Modified time is just the most recently modified file.
472    * For JSP files, this is overwritten to always return 0.
473    */

474   public long _caucho_lastModified()
475   {
476     if (_cacheDepends == null) {
477       return 0;
478     }
479     else {
480       return calculateLastModified(_depends, _cacheDepends);
481     }
482   }
483
484   /**
485    * Calculate the last modified time for all the dependencies. The
486    * last modified time is the time of the most recently changed
487    * cache or source file.
488    *
489    * @param depends list of the source file dependencies
490    * @param cacheDepends list of the cache dependencies
491    *
492    * @return the last modified time in milliseconds
493    */

494   public static long calculateLastModified(ArrayList JavaDoc<PersistentDependency> depends,
495                                            ArrayList JavaDoc<Depend> cacheDepends)
496   {
497       long lastModified = 0;
498       
499       for (int i = 0; i < depends.size(); i++) {
500         PersistentDependency dependency = depends.get(i);
501
502         if (dependency instanceof Depend) {
503           Depend depend = (Depend) dependency;
504           long modified = depend.getLastModified();
505           if (lastModified < modified)
506             lastModified = modified;
507         }
508       }
509
510       for (int i = 0; cacheDepends != null && i < cacheDepends.size(); i++) {
511     Depend depend = cacheDepends.get(i);
512         long modified = depend.getLastModified();
513         if (lastModified < modified)
514           lastModified = modified;
515       }
516
517       return lastModified;
518   }
519   
520   /**
521    * The extended service method creates JavaScript global variables
522    * from a property map.
523    *
524    * <p>This method only makes sense for JavaScript templates. To pass
525    * variables to Java templates, use the setAttribute() method of the
526    * request.
527    *
528    * @param properties hashmap of objects to create as JavaScript globals.
529    */

530   public void pageservice(HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc res)
531     throws IOException JavaDoc, ServletException JavaDoc
532   {
533     PageManager.Entry entry = _entry;
534     if (entry != null)
535       entry.accessPage();
536     
537     long lastModified = getLastModified(req);
538
539     if (lastModified > 0) {
540       if (_calendar == null)
541         _calendar = new QDate();
542
543       String JavaDoc etag = _etag;
544       if (lastModified != _lastModified) {
545         CharBuffer cb = new CharBuffer();
546         cb.append('"');
547         Base64.encode(cb, lastModified);
548         cb.append('"');
549         etag = cb.close();
550         _etag = etag;
551
552         synchronized (_calendar) {
553           _calendar.setGMTTime(lastModified);
554           _lastModifiedString = _calendar.printDate();
555         }
556     
557     _lastModified = lastModified;
558       }
559       
560       String JavaDoc ifMatch = req.getHeader("If-None-Match");
561       if (etag.equals(ifMatch)) {
562     res.sendError(res.SC_NOT_MODIFIED);
563     return;
564       }
565
566       String JavaDoc ifModifiedSince = req.getHeader("If-Modified-Since");
567       if (_lastModifiedString.equals(ifModifiedSince)) {
568     res.sendError(res.SC_NOT_MODIFIED);
569     return;
570       }
571
572       res.setHeader("ETag", etag);
573       res.setHeader("Last-Modified", _lastModifiedString);
574     }
575
576     if (res instanceof CauchoResponse) {
577       service(req, res);
578     }
579     else {
580       // The wrapping is needed to handle the output stream.
581
ToCharResponseAdapter resAdapt = ToCharResponseAdapter.create(res);
582       // resAdapt.setRequest(req);
583
//resAdapt.init(res);
584

585       try {
586         service(req, resAdapt);
587       } finally {
588         resAdapt.close();
589     ToCharResponseAdapter.free(resAdapt);
590       }
591     }
592   }
593
594   protected void setDead()
595   {
596     _isDead = true;
597   }
598
599   public boolean isDead()
600   {
601     return _isDead;
602   }
603
604   /**
605    * Starts recompiling. Returns false if the recompiling has already
606    * started or if the page has already been destroyed.
607    */

608   public boolean startRecompiling()
609   {
610     boolean allowRecompiling;
611     
612     synchronized (this) {
613       allowRecompiling = _isDead || ! _isRecompiling;
614       _isRecompiling = true;
615     }
616
617     return allowRecompiling;
618   }
619
620   String JavaDoc getErrorPage() { return null; }
621
622   /**
623    * Marks the page as used.
624    */

625   public void _caucho_use()
626   {
627     synchronized (this) {
628       _useCount++;
629     }
630   }
631
632   /**
633    * Marks the page as free.
634    */

635   public void _caucho_free()
636   {
637     synchronized (this) {
638       _useCount--;
639     }
640
641     if (_useCount <= 0)
642       destroy();
643   }
644
645   public void destroy()
646   {
647     if (_isDead)
648       return;
649     
650     _isDead = true;
651     /*
652     if (! _isDead)
653       throw new IllegalStateException();
654     */

655
656     _entry = null;
657
658     Thread JavaDoc thread = Thread.currentThread();
659     ClassLoader JavaDoc oldLoader = thread.getContextClassLoader();
660     try {
661       thread.setContextClassLoader(getClass().getClassLoader());
662
663       _caucho_log.fine(getClass().getName() + " destroy");
664     } finally {
665       thread.setContextClassLoader(oldLoader);
666     }
667   }
668 }
669
Popular Tags