001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.jsp;
031:
032: import com.caucho.java.JavaCompiler;
033: import com.caucho.java.LineMap;
034: import com.caucho.jsp.cfg.JspConfig;
035: import com.caucho.jsp.cfg.JspPropertyGroup;
036: import com.caucho.jsp.java.JspTagSupport;
037: import com.caucho.jsp.java.TagTaglib;
038: import com.caucho.log.Log;
039: import com.caucho.server.webapp.WebApp;
040: import com.caucho.vfs.Path;
041: import com.caucho.vfs.PersistentDependency;
042: import com.caucho.xml.Xml;
043:
044: import org.xml.sax.SAXException;
045:
046: import javax.servlet.jsp.tagext.TagInfo;
047: import javax.servlet.jsp.tagext.TagLibraryInfo;
048: import java.io.FileNotFoundException;
049: import java.io.IOException;
050: import java.io.InputStream;
051: import java.util.ArrayList;
052: import java.util.logging.Level;
053: import java.util.logging.Logger;
054:
055: /**
056: * Compilation interface for JSP pages.
057: */
058: public class JspCompilerInstance {
059: private static final Logger log = Log
060: .open(JspCompilerInstance.class);
061:
062: // The underlying compiler
063: private JspCompiler _jspCompiler;
064:
065: // The path to the JSP source
066: private Path _jspPath;
067:
068: // The JSP uri (user-name)
069: private String _uri;
070:
071: // The JSP class name
072: private String _className;
073:
074: private JspPropertyGroup _jspPropertyGroup;
075:
076: // The builder
077: private JspBuilder _jspBuilder;
078:
079: // true for XML parsing
080: private boolean _isXml;
081:
082: // true for prototype parsing.
083: private boolean _isPrototype;
084:
085: // true for generated source (like XTP)
086: private boolean _isGeneratedSource;
087:
088: // The parse state
089: private ParseState _parseState;
090:
091: // The tag manager
092: private ParseTagManager _tagManager;
093:
094: // The parser
095: private JspParser _parser;
096:
097: // The compiled page
098: private Page _page;
099:
100: // The generator
101: private JspGenerator _generator;
102:
103: private ArrayList<String> _preludeList = new ArrayList<String>();
104: private ArrayList<String> _codaList = new ArrayList<String>();
105:
106: private ArrayList<PersistentDependency> _dependList = new ArrayList<PersistentDependency>();
107:
108: /**
109: * Creates a JSP compiler instance.
110: */
111: JspCompilerInstance(JspCompiler compiler) {
112: _jspCompiler = compiler;
113:
114: _isXml = _jspCompiler.isXml();
115: }
116:
117: /**
118: * Sets the builder.
119: */
120: void setJspBuilder(JspBuilder builder) {
121: _jspBuilder = builder;
122: }
123:
124: /**
125: * Sets the path.
126: */
127: void setJspPath(Path path) {
128: _jspPath = path;
129: }
130:
131: /**
132: * Sets the uri
133: */
134: void setURI(String uri) {
135: _uri = uri;
136: }
137:
138: /**
139: * Sets true for xml
140: */
141: void setXML(boolean isXml) {
142: _isXml = isXml;
143: }
144:
145: /*
146: * Sets true for generated source
147: */
148: void setGeneratedSource(boolean isGeneratedSource) {
149: _isGeneratedSource = isGeneratedSource;
150: }
151:
152: /*
153: * Sets true for generated source
154: */
155: public boolean isGeneratedSource() {
156: return _isGeneratedSource;
157: }
158:
159: /**
160: * Sets the class name.
161: */
162: void setClassName(String className) {
163: _className = className;
164: }
165:
166: /**
167: * Adds a dependency.
168: */
169: public void addDepend(PersistentDependency depend) {
170: _dependList.add(depend);
171: }
172:
173: /**
174: * Adds a dependency.
175: */
176: public void addDependList(ArrayList<PersistentDependency> dependList) {
177: if (dependList != null)
178: _dependList.addAll(dependList);
179: }
180:
181: /**
182: * Returns the jsp configuration.
183: */
184: public JspPropertyGroup getJspPropertyGroup() {
185: return _jspPropertyGroup;
186: }
187:
188: /**
189: * Returns true for prototype compilation.
190: */
191: public boolean isPrototype() {
192: return _isPrototype;
193: }
194:
195: /**
196: * Set true for prototype compilation.
197: */
198: public void setPrototype(boolean prototype) {
199: _isPrototype = prototype;
200: }
201:
202: /**
203: * Initialize the instance.
204: */
205: void init() throws Exception {
206: _parseState = new ParseState();
207:
208: String uriPwd;
209: if (_uri != null) {
210: int p = _uri.lastIndexOf('/');
211: uriPwd = p <= 0 ? "/" : _uri.substring(0, p + 1);
212: } else {
213: uriPwd = "/";
214: }
215:
216: _parseState.setUriPwd(uriPwd);
217:
218: if (_className == null)
219: _className = JavaCompiler.mangleName("jsp/" + _uri);
220:
221: // default to true if ends with x
222: if (_uri.endsWith("x"))
223: _parseState.setXml(true);
224:
225: WebApp app = _jspCompiler.getWebApp();
226: Path appDir = _jspCompiler.getAppDir();
227: if (appDir == null && app != null)
228: appDir = app.getAppDir();
229:
230: if (app != null && app.has23Config())
231: _parseState.setELIgnoredDefault(true);
232:
233: JspConfig jspConfig = null;
234:
235: if (jspConfig == null && app != null)
236: jspConfig = (JspConfig) app.getExtension("jsp-config");
237:
238: ArrayList<JspPropertyGroup> jspList = new ArrayList<JspPropertyGroup>();
239: _jspPropertyGroup = null;
240:
241: if (_jspPropertyGroup == null) {
242: _jspPropertyGroup = _jspCompiler.getJspPropertyGroup();
243:
244: if (_jspPropertyGroup != null) {
245: jspList.add(_jspPropertyGroup);
246: }
247: }
248:
249: if (_jspPropertyGroup == null && app != null) {
250: _jspPropertyGroup = app.getJsp();
251:
252: if (_jspPropertyGroup != null)
253: jspList.add(_jspPropertyGroup);
254: }
255:
256: if (_jspPropertyGroup == null) {
257: _jspPropertyGroup = _jspCompiler.getJspPropertyGroup();
258:
259: if (_jspPropertyGroup != null)
260: jspList.add(_jspPropertyGroup);
261: }
262:
263: if (jspConfig != null) {
264: jspList.addAll(jspConfig.findJspPropertyGroupList(_uri));
265:
266: _parseState.setELIgnoredDefault(false);
267: }
268:
269: JspResourceManager resourceManager = _jspCompiler
270: .getResourceManager();
271: if (resourceManager != null) {
272: } else if (app != null)
273: resourceManager = new AppResourceManager(app);
274: else {
275: resourceManager = new AppDirResourceManager(appDir);
276: }
277:
278: TagFileManager tagFileManager = _jspCompiler
279: .getTagFileManager();
280:
281: TaglibManager taglibManager = _jspCompiler.getTaglibManager();
282:
283: JspPageConfig pageConfig = new JspPageConfig();
284:
285: for (JspPropertyGroup jspPropertyGroup : jspList) {
286: ArrayList<String> preludeList = jspPropertyGroup
287: .getIncludePreludeList();
288: for (int i = 0; preludeList != null
289: && i < preludeList.size(); i++) {
290: String prelude = preludeList.get(i);
291: _preludeList.add(prelude);
292: }
293:
294: ArrayList<String> codaList = jspPropertyGroup
295: .getIncludeCodaList();
296: for (int i = 0; codaList != null && i < codaList.size(); i++) {
297: String coda = codaList.get(i);
298: _codaList.add(coda);
299: }
300:
301: _parseState.setJspPropertyGroup(jspPropertyGroup);
302: _parseState.setSession(jspPropertyGroup.isSession());
303: _parseState.setScriptingInvalid(jspPropertyGroup
304: .isScriptingInvalid());
305:
306: if (jspPropertyGroup.isELIgnored() != null)
307: _parseState.setELIgnored(Boolean.TRUE
308: .equals(jspPropertyGroup.isELIgnored()));
309: _parseState.setVelocityEnabled(jspPropertyGroup
310: .isVelocityEnabled());
311: _parseState.setPageEncoding(jspPropertyGroup
312: .getPageEncoding());
313:
314: if (Boolean.TRUE.equals(jspPropertyGroup.isXml()))
315: _parseState.setXml(true);
316:
317: if (Boolean.FALSE.equals(jspPropertyGroup.isXml()))
318: _parseState.setForbidXml(true);
319:
320: if (jspPropertyGroup.getPageEncoding() != null) {
321: try {
322: _parseState.setPageEncoding(jspPropertyGroup
323: .getPageEncoding());
324: } catch (JspParseException e) {
325: }
326: }
327:
328: pageConfig.setStaticEncoding(jspPropertyGroup
329: .isStaticEncoding());
330:
331: _parseState
332: .setRecycleTags(jspPropertyGroup.isRecycleTags());
333:
334: _parseState.setTrimWhitespace(jspPropertyGroup
335: .isTrimDirectiveWhitespaces());
336: _parseState
337: .setDeferredSyntaxAllowedAsLiteral(jspPropertyGroup
338: .isDeferredSyntaxAllowedAsLiteral());
339:
340: if (jspPropertyGroup.getTldFileSet() != null)
341: taglibManager.setTldFileSet(jspPropertyGroup
342: .getTldFileSet());
343: }
344:
345: _parseState.setResourceManager(resourceManager);
346: LineMap lineMap = null;
347:
348: _tagManager = new ParseTagManager(resourceManager,
349: taglibManager, tagFileManager);
350:
351: _jspBuilder = new com.caucho.jsp.java.JavaJspBuilder();
352: _jspBuilder.setParseState(_parseState);
353: _jspBuilder.setJspCompiler(_jspCompiler);
354: _jspBuilder.setJspPropertyGroup(_jspPropertyGroup);
355: _jspBuilder.setTagManager(_tagManager);
356: _jspBuilder.setPageConfig(pageConfig);
357: _jspBuilder.setPrototype(_isPrototype);
358:
359: _parser = new JspParser();
360: _parser.setJspBuilder(_jspBuilder);
361: _parser.setParseState(_parseState);
362: _parser.setTagManager(_tagManager);
363:
364: _jspBuilder.setJspParser(_parser);
365:
366: /*
367: for (int i = 0; i < _preludeList.size(); i++)
368: _parser.addPrelude(_preludeList.get(i));
369:
370: for (int i = 0; i < _codaList.size(); i++)
371: _parser.addCoda(_codaList.get(i));
372: */
373: }
374:
375: public Page compile() throws Exception {
376: LineMap lineMap = null;
377: if (_page != null)
378: throw new IllegalStateException(
379: "JspCompilerInstance cannot be reused");
380:
381: try {
382: JspGenerator generator = generate();
383:
384: lineMap = generator.getLineMap();
385:
386: String encoding = _parseState.getCharEncoding();
387:
388: _jspCompiler.compilePending();
389:
390: boolean isAutoCompile = true;
391: if (_jspPropertyGroup != null)
392: isAutoCompile = _jspPropertyGroup.isAutoCompile();
393:
394: Page page;
395: if (!generator.isStatic()) {
396: compileJava(_jspPath, _className, lineMap, encoding);
397:
398: page = _jspCompiler.loadPage(_className, isAutoCompile);
399: } else {
400: page = _jspCompiler.loadStatic(_className, _parseState
401: .isOptionalSession());
402: page._caucho_addDepend(generator.getDependList());
403: page._caucho_setContentType(_parseState
404: .getContentType());
405: }
406:
407: return page;
408: } catch (JspParseException e) {
409: e.setLineMap(lineMap);
410: e.setErrorPage(_parseState.getErrorPage());
411: throw e;
412: } catch (SAXException e) {
413: if (e.getCause() instanceof JspParseException) {
414: JspParseException subE = (JspParseException) e
415: .getCause();
416:
417: subE.setLineMap(lineMap);
418: subE.setErrorPage(_parseState.getErrorPage());
419: throw subE;
420: } else {
421: JspParseException exn = new JspParseException(e);
422: exn.setErrorPage(_parseState.getErrorPage());
423: exn.setLineMap(lineMap);
424:
425: throw exn;
426: }
427: } catch (FileNotFoundException e) {
428: throw e;
429: } catch (IOException e) {
430: JspParseException exn = new JspParseException(e);
431: exn.setLineMap(lineMap);
432: exn.setErrorPage(_parseState.getErrorPage());
433:
434: throw exn;
435: } catch (Throwable e) {
436: JspParseException exn = new JspParseException(e);
437: exn.setLineMap(lineMap);
438: exn.setErrorPage(_parseState.getErrorPage());
439:
440: throw exn;
441: }
442: }
443:
444: public JspGenerator generate() throws Exception {
445: if (_page != null)
446: throw new IllegalStateException(
447: "JspCompilerInstance cannot be reused");
448:
449: boolean isXml = _parseState.isXml();
450: boolean isForbidXml = _parseState.isForbidXml();
451:
452: ParseState parseState = _parser.getParseState();
453:
454: try {
455: _parser.getParseState().setBuilder(_jspBuilder);
456:
457: for (String prelude : _preludeList) {
458: parseState.setXml(false);
459: parseState.setForbidXml(false);
460: _parser.parse(parseState.getResourceManager()
461: .resolvePath(prelude), prelude);
462: }
463:
464: _parser.getParseState().setXml(isXml);
465: _parser.getParseState().setForbidXml(isForbidXml);
466:
467: if (isXml) {
468: _parseState.setELIgnoredDefault(false);
469:
470: Xml xml = new Xml();
471: xml
472: .setContentHandler(new JspContentHandler(
473: _jspBuilder));
474: _jspPath.setUserPath(_uri);
475: xml.setNamespaceAware(true);
476: xml.parse(_jspPath);
477: } else {
478: WebApp app = _jspCompiler.getWebApp();
479:
480: // jsp/0135
481: /*
482: if (_jspPropertyGroup == null && app != null && app.has23Config())
483: _parseState.setELIgnored(true);
484: */
485:
486: _parser.parse(_jspPath, _uri);
487: }
488:
489: for (String coda : _codaList) {
490: parseState.setXml(false);
491: parseState.setForbidXml(false);
492: _parser.parse(parseState.getResourceManager()
493: .resolvePath(coda), coda);
494: }
495:
496: JspGenerator generator = _jspBuilder.getGenerator();
497: generator.setJspCompilerInstance(this );
498:
499: for (int i = 0; i < _dependList.size(); i++)
500: generator.addDepend(_dependList.get(i));
501:
502: generator.validate();
503:
504: generator.generate(_jspPath, _className);
505:
506: return generator;
507: } catch (JspParseException e) {
508: e.setErrorPage(_parseState.getErrorPage());
509: throw e;
510: } catch (SAXException e) {
511: if (e.getCause() instanceof JspParseException) {
512: JspParseException subE = (JspParseException) e
513: .getCause();
514:
515: subE.setErrorPage(_parseState.getErrorPage());
516: throw subE;
517: } else {
518: JspParseException exn = new JspParseException(e);
519: exn.setErrorPage(_parseState.getErrorPage());
520:
521: throw exn;
522: }
523: } catch (FileNotFoundException e) {
524: throw e;
525: } catch (IOException e) {
526: JspParseException exn = new JspParseException(e);
527: exn.setErrorPage(_parseState.getErrorPage());
528:
529: throw exn;
530: }
531: }
532:
533: public TagInfo compileTag(TagLibraryInfo taglib) throws Exception {
534: TagInfo preloadTag = preloadTag(taglib);
535:
536: if (preloadTag != null)
537: return preloadTag;
538:
539: return generateTag(taglib);
540: }
541:
542: private TagInfo preloadTag(TagLibraryInfo taglib) {
543: try {
544: JspTagSupport tag = (JspTagSupport) _jspCompiler.loadClass(
545: _className, true);
546:
547: if (tag == null)
548: return null;
549:
550: tag.init(_jspCompiler.getAppDir());
551:
552: if (tag._caucho_isModified())
553: return null;
554:
555: return tag._caucho_getTagInfo(taglib);
556: } catch (Throwable e) {
557: return null;
558: }
559: }
560:
561: private TagInfo generateTag(TagLibraryInfo taglib) throws Exception {
562: LineMap lineMap = null;
563: if (_page != null)
564: throw new IllegalStateException(
565: "JspCompilerInstance cannot be reused");
566:
567: try {
568: boolean isXml = _isXml;
569:
570: if (_jspPropertyGroup != null && !isXml
571: && _jspPropertyGroup.isXml() != null)
572: isXml = Boolean.TRUE.equals(_jspPropertyGroup.isXml());
573:
574: if (_jspPropertyGroup != null
575: && Boolean.FALSE.equals(_jspPropertyGroup.isXml()))
576: _parseState.setForbidXml(true);
577:
578: _parseState.setXml(isXml);
579:
580: if (_jspCompiler.addTag(_className)) {
581: _isPrototype = true;
582: _jspBuilder.setPrototype(true);
583: }
584:
585: _parseState.setTag(true);
586: _isXml = isXml;
587:
588: if (isXml) {
589: _parseState.setELIgnoredDefault(false);
590:
591: Xml xml = new Xml();
592: xml
593: .setContentHandler(new JspContentHandler(
594: _jspBuilder));
595: _jspPath.setUserPath(_uri);
596: xml.setNamespaceAware(true);
597: xml.parse(_jspPath);
598: } else
599: _parser.parseTag(_jspPath, _uri);
600:
601: _generator = _jspBuilder.getGenerator();
602:
603: if (_isPrototype) {
604: return _generator.generateTagInfo(_className, taglib);
605: }
606:
607: _generator.validate();
608:
609: _generator.generate(_jspPath, _className);
610:
611: if (_jspCompiler.hasRecursiveCompile()) {
612: _jspCompiler.addPending(this );
613:
614: return _generator.generateTagInfo(_className, taglib);
615: }
616:
617: return completeTag(taglib);
618: } catch (JspParseException e) {
619: e.setLineMap(lineMap);
620: e.setErrorPage(_parseState.getErrorPage());
621: throw e;
622: } catch (FileNotFoundException e) {
623: throw e;
624: } catch (IOException e) {
625: JspParseException exn = new JspParseException(e);
626: exn.setErrorPage(_parseState.getErrorPage());
627: exn.setLineMap(lineMap);
628: throw exn;
629: }
630: }
631:
632: TagInfo completeTag() throws Exception {
633: return completeTag(new TagTaglib("x", "uri"));
634: }
635:
636: TagInfo completeTag(TagLibraryInfo taglib) throws Exception {
637: LineMap lineMap = null;
638:
639: try {
640: lineMap = _generator.getLineMap();
641:
642: String encoding = _parseState.getCharEncoding();
643:
644: compileJava(_jspPath, _className, lineMap, encoding);
645:
646: JspTagSupport tag = (JspTagSupport) _jspCompiler.loadClass(
647: _className, true);
648:
649: tag.init(_jspCompiler.getAppDir());
650:
651: return tag._caucho_getTagInfo(taglib);
652: // Page page = _jspCompiler.loadClass(_className);
653: } catch (JspParseException e) {
654: e.setLineMap(lineMap);
655: e.setErrorPage(_parseState.getErrorPage());
656: throw e;
657: } catch (FileNotFoundException e) {
658: throw e;
659: } catch (IOException e) {
660: JspParseException exn = new JspParseException(e);
661: exn.setErrorPage(_parseState.getErrorPage());
662: exn.setLineMap(lineMap);
663: throw exn;
664: } catch (Throwable e) {
665: JspParseException exn = new JspParseException(e);
666: exn.setErrorPage(_parseState.getErrorPage());
667: exn.setLineMap(lineMap);
668: throw exn;
669: }
670: }
671:
672: private void compileJava(Path path, String className,
673: LineMap lineMap, String charEncoding) throws Exception {
674: JavaCompiler compiler = JavaCompiler.create(null);
675: compiler.setClassDir(_jspCompiler.getClassDir());
676: // compiler.setEncoding(charEncoding);
677: String fileName = className.replace('.', '/') + ".java";
678:
679: compiler.compile(fileName, lineMap);
680:
681: /*
682: boolean remove = true;
683: try {
684: compiler.compile(fileName, lineMap);
685: remove = false;
686: } finally {
687: if (remove)
688: Vfs.lookup(fileName).remove();
689: }
690: */
691:
692: Path classDir = _jspCompiler.getClassDir();
693: Path classPath = classDir.lookup(className.replace('.', '/')
694: + ".class");
695: Path smapPath = classDir.lookup(fileName + ".smap");
696:
697: // jsp/18p1
698: // compiler.mergeSmap(classPath, smapPath);
699: }
700:
701: private void readSmap(ClassLoader loader, String className) {
702: if (loader == null)
703: return;
704:
705: String smapName = className.replace('.', '/') + ".java.smap";
706:
707: InputStream is = null;
708: try {
709: is = loader.getResourceAsStream(smapName);
710: } catch (Exception e) {
711: log.log(Level.FINE, e.toString(), e);
712: } finally {
713: if (is != null) {
714: try {
715: is.close();
716: } catch (IOException e) {
717: }
718: }
719: }
720: }
721: }
|