001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.apache.jasper.compiler;
043:
044: import java.io.File;
045: import java.lang.reflect.Field;
046: import java.net.MalformedURLException;
047: import java.net.URI;
048: import java.net.URISyntaxException;
049: import java.net.URL;
050: import java.util.Enumeration;
051: import java.util.HashSet;
052: import java.util.Hashtable;
053: import java.util.Iterator;
054: import java.util.List;
055: import java.util.Map;
056: import java.util.Set;
057: import java.util.Vector;
058: import java.util.logging.Level;
059: import java.util.logging.Logger;
060: import javax.servlet.jsp.JspException;
061: import javax.servlet.jsp.PageContext;
062: import javax.servlet.jsp.tagext.TagFileInfo;
063: import javax.servlet.jsp.tagext.TagLibraryInfo;
064: import org.apache.jasper.JasperException;
065: import org.apache.jasper.JspCompilationContext;
066: import org.apache.jasper.Options;
067:
068: /**
069: *
070: * @author Petr Jiricka
071: */
072: public class GetParseData {
073:
074: private static final Logger LOGGER = Logger
075: .getLogger(GetParseData.class.getName());
076:
077: private final JspCompilationContext ctxt;
078:
079: private final Options options;
080: private final CompilerHacks compHacks;
081: private int errorReportingMode;
082:
083: private org.netbeans.modules.web.jsps.parserapi.Node.Nodes nbNodes;
084: private org.netbeans.modules.web.jsps.parserapi.PageInfo nbPageInfo;
085: private Throwable parseException;
086:
087: /** Creates a new instance of ExtractPageData */
088: public GetParseData(JspCompilationContext ctxt,
089: int errorReportingMode) {
090: this .ctxt = ctxt;
091: this .errorReportingMode = errorReportingMode;
092: options = ctxt.getOptions();
093: compHacks = new CompilerHacks(ctxt);
094: }
095:
096: public org.netbeans.modules.web.jsps.parserapi.Node.Nodes getNbNodes() {
097: return nbNodes;
098: }
099:
100: public org.netbeans.modules.web.jsps.parserapi.PageInfo getNbPageInfo() {
101: return nbPageInfo;
102: }
103:
104: public Throwable getParseException() {
105: return parseException;
106: }
107:
108: /** Code in this method copied over and adapted from Compiler.generateJava()
109: **/
110: public void parse() {
111: Node.Nodes pageNodes = null;
112: PageInfo pageInfo = null;
113: String xmlView = null;
114: try {
115: //String smapStr = null;
116:
117: // long t1=System.currentTimeMillis();
118:
119: // Setup page info area
120: Compiler comp = compHacks.getCompiler();
121: pageInfo = comp.getPageInfo();
122: ErrorDispatcher errDispatcher = comp.getErrorDispatcher();
123:
124: // pageInfo = new PageInfo(new BeanRepository(ctxt.getClassLoader(),
125: // errDispatcher));
126:
127: JspConfig jspConfig = options.getJspConfig();
128: JspProperty jspProperty = jspConfig.findJspProperty(ctxt
129: .getJspFile());
130:
131: /*
132: * If the current uri is matched by a pattern specified in
133: * a jsp-property-group in web.xml, initialize pageInfo with
134: * those properties.
135: */
136: pageInfo.setELIgnored(JspUtil.booleanValue(jspProperty
137: .isELIgnored()));
138: pageInfo.setScriptingInvalid(JspUtil
139: .booleanValue(jspProperty.isScriptingInvalid()));
140: if (jspProperty.getIncludePrelude() != null) {
141: pageInfo.setIncludePrelude(jspProperty
142: .getIncludePrelude());
143: }
144: if (jspProperty.getIncludeCoda() != null) {
145: pageInfo.setIncludeCoda(jspProperty.getIncludeCoda());
146: }
147: // String javaFileName = ctxt.getServletJavaFileName();
148:
149: // Setup the ServletWriter
150: // String javaEncoding = ctxt.getOptions().getJavaEncoding();
151: // OutputStreamWriter osw = null;
152: // try {
153: // osw = new OutputStreamWriter(new FileOutputStream(javaFileName),
154: // javaEncoding);
155: // } catch (UnsupportedEncodingException ex) {
156: // errDispatcher.jspError("jsp.error.needAlternateJavaEncoding", javaEncoding);
157: // }
158:
159: // ServletWriter writer = new ServletWriter(new PrintWriter(osw));
160: // ctxt.setWriter(writer);
161:
162: // Reset the temporary variable counter for the generator.
163: JspUtil.resetTemporaryVariableName();
164:
165: // Parse the file
166: ParserController parserCtl = new ParserController(ctxt,
167: comp);
168: pageNodes = parserCtl.parse(ctxt.getJspFile());
169:
170: // if (ctxt.isPrototypeMode()) {
171: // // generate prototype .java file for the tag file
172: // Generator.generate(writer, this, pageNodes);
173: // writer.close();
174: // return null;
175: // }
176:
177: // Generate FunctionMapper (used for validation of EL expressions and
178: // code generation)
179: // pageInfo.setFunctionMapper(new FunctionMapperImpl(this));
180:
181: // Validate and process attributes
182: // Validator.validate(comp, pageNodes);
183: xmlView = NbValidator.validate(comp, pageNodes);
184:
185: // long t2=System.currentTimeMillis();
186: // Dump out the page (for debugging)
187: // Dumper.dump(pageNodes);
188:
189: // Collect page info
190: Collector.collect(comp, pageNodes);
191:
192: // Compile (if necessary) and load the tag files referenced in
193: // this compilation unit.
194:
195: // PENDING - we may need to process tag files somehow
196: // TagFileProcessor tfp = new TagFileProcessor();
197: // tfp.loadTagFiles(comp, pageNodes);
198:
199: // Try to obtain tagInfo if the page is a tag file
200: if (ctxt.isTagFile()) {
201: // find out the dir for fake tag library
202: String tagDir = ctxt.getJspFile();
203: int lastIndex = tagDir.lastIndexOf('/');
204: int lastDotIndex = tagDir.lastIndexOf('.');
205: String tagName;
206: if (lastDotIndex > 0) {
207: tagName = tagDir.substring(lastIndex + 1,
208: lastDotIndex);
209: } else {
210: tagName = tagDir.substring(lastIndex + 1);
211: }
212: tagDir = tagDir.substring(0,
213: tagDir.lastIndexOf('/') + 1);
214:
215: // we need to compile the tag file to a virtual tag library to obtain its tag info
216: ImplicitTagLibraryInfo tagLibrary = new ImplicitTagLibraryInfo(
217: ctxt, parserCtl, "virtual", tagDir,
218: errDispatcher); //NOI18N
219: ctxt.setTagInfo(tagLibrary.getTagFile(tagName)
220: .getTagInfo());
221: }
222: // long t3=System.currentTimeMillis();
223:
224: // Determine which custom tag needs to declare which scripting vars
225: ScriptingVariabler.set(pageNodes, errDispatcher);
226:
227: // Optimizations by Tag Plugins
228: TagPluginManager tagPluginManager = options
229: .getTagPluginManager();
230: tagPluginManager.apply(pageNodes, errDispatcher, pageInfo);
231:
232: // Generate static funciton mapper codes.
233: ELFunctionMapper.map(comp, pageNodes);
234:
235: // generate servlet .java file
236: // Generator.generate(writer, comp, pageNodes);
237: // writer.close();
238: // The writer is only used during the compile, dereference
239: // it in the JspCompilationContext when done to allow it
240: // to be GC'd and save memory.
241: // ctxt.setWriter(null);
242:
243: // long t4=System.currentTimeMillis();
244: // if( t4-t1 > 500 ) {
245: // log.debug("Generated "+ javaFileName + " total=" +
246: // (t4-t1) + " generate=" + ( t4-t3 ) + " validate=" + ( t2-t1 ));
247: // }
248:
249: //JSR45 Support - note this needs to be checked by a JSR45 guru
250: // if (! options.isSmapSuppressed()) {
251: // String smapStr = SmapUtil.generateSmap(ctxt, pageNodes);
252: // }
253:
254: // If any proto type .java and .class files was generated,
255: // the prototype .java may have been replaced by the current
256: // compilation (if the tag file is self referencing), but the
257: // .class file need to be removed, to make sure that javac would
258: // generate .class again from the new .java file just generated.
259:
260: // PENDING - we may need to process tag files somehow
261: // tfp.removeProtoTypeFiles(ctxt.getClassFileName());
262: } catch (ThreadDeath t) {
263: throw t;
264: } catch (Throwable t) {
265: parseException = t;
266: } finally {
267: // convert the nodes
268: try {
269: if (pageNodes != null) {
270: nbNodes = convertNodes(pageNodes);
271: }
272: } catch (JasperException e) {
273: if (parseException == null) {
274: parseException = e;
275: }
276: }
277: // convert the pageInfo
278: try {
279: if (pageInfo != null) {
280: // xmlView may be null
281: nbPageInfo = convertPageInfo(pageInfo, xmlView,
282: ctxt);
283: }
284: } catch (JspException e) {
285: if (parseException == null) {
286: parseException = e;
287: }
288: }
289: }
290: // return smapStr;
291: }
292:
293: private static org.netbeans.modules.web.jsps.parserapi.Node.Nodes convertNodes(
294: Node.Nodes nodes) throws JasperException {
295: org.netbeans.modules.web.jsps.parserapi.Node.Nodes nbNodes = NodeConverterVisitor
296: .convertNodes(nodes);
297: return nbNodes;
298: }
299:
300: private static org.netbeans.modules.web.jsps.parserapi.PageInfo convertPageInfo(
301: PageInfo pageInfo, String xmlView,
302: JspCompilationContext ctxt) throws JspException {
303: PageInfoImpl nbPageInfo = new PageInfoImpl(
304: getTaglibsMapReflect(pageInfo, ctxt),
305: getJSPPrefixMapperReflect(pageInfo),
306: getXMLPrefixMapperReflect(pageInfo),
307: ((CompilerHacks.HackPageInfo) pageInfo)
308: .getApproxXmlPrefixMapper(), pageInfo
309: .getImports(), pageInfo.getDependants(),
310: pageInfo.getIncludePrelude(),
311: pageInfo.getIncludeCoda(),
312: getPluginDclsReflect(pageInfo),
313: getPrefixesReflect(pageInfo));
314: nbPageInfo.setLanguage(pageInfo.getLanguage());
315: nbPageInfo.setExtends(pageInfo.getExtends());
316: nbPageInfo.setContentType(pageInfo.getContentType());
317: nbPageInfo.setSession(pageInfo.getSession());
318: nbPageInfo.setBufferValue(pageInfo.getBufferValue());
319: nbPageInfo.setAutoFlush(pageInfo.getAutoFlush());
320: nbPageInfo.setIsThreadSafe(pageInfo.getIsThreadSafe());
321: nbPageInfo.setIsErrorPage(pageInfo.getIsErrorPage());
322: nbPageInfo.setErrorPage(pageInfo.getErrorPage());
323: nbPageInfo.setScriptless(pageInfo.isScriptless());
324: nbPageInfo.setScriptingInvalid(pageInfo.isScriptingInvalid());
325: nbPageInfo.setELIgnored(pageInfo.isELIgnored());
326: nbPageInfo.setOmitXmlDecl(pageInfo.getOmitXmlDecl());
327: nbPageInfo.setIsJspPrefixHijacked(pageInfo
328: .isJspPrefixHijacked());
329: nbPageInfo.setDoctypeName(pageInfo.getDoctypeName());
330: nbPageInfo.setDoctypeSystem(pageInfo.getDoctypeSystem());
331: nbPageInfo.setDoctypePublic(pageInfo.getDoctypePublic());
332: nbPageInfo.setHasJspRoot(pageInfo.hasJspRoot());
333: nbPageInfo
334: .setBeans(createBeanData(pageInfo.getBeanRepository()));
335: // the xml view
336: nbPageInfo.setXMLView(xmlView);
337:
338: nbPageInfo.setTagFile(ctxt.isTagFile());
339: nbPageInfo.setTagInfo(ctxt.getTagInfo());
340:
341: return nbPageInfo;
342: }
343:
344: private static org.netbeans.modules.web.jsps.parserapi.PageInfo.BeanData[] createBeanData(
345: BeanRepository rep) {
346: try {
347: initBeanRepositoryFields();
348: Vector sessionBeans = (Vector) sessionBeansF.get(rep);
349: Vector pageBeans = (Vector) pageBeansF.get(rep);
350: Vector appBeans = (Vector) appBeansF.get(rep);
351: Vector requestBeans = (Vector) requestBeansF.get(rep);
352: Hashtable beanTypes = (Hashtable) beanTypesF.get(rep);
353: int size = beanTypes.size();
354: org.netbeans.modules.web.jsps.parserapi.PageInfo.BeanData bd[] = new org.netbeans.modules.web.jsps.parserapi.PageInfo.BeanData[size];
355: Iterator it = beanTypes.keySet().iterator();
356: int index = 0;
357: while (it.hasNext()) {
358: String id = (String) it.next();
359: String type = (String) beanTypes.get(id);
360: int scope = PageContext.PAGE_SCOPE;
361: if (sessionBeans.contains(id)) {
362: scope = PageContext.SESSION_SCOPE;
363: }
364: if (appBeans.contains(id)) {
365: scope = PageContext.APPLICATION_SCOPE;
366: }
367: if (requestBeans.contains(id)) {
368: scope = PageContext.REQUEST_SCOPE;
369: }
370:
371: bd[index] = new BeanDataImpl(id, scope, type);
372: ++index;
373: }
374: return bd;
375: } catch (IllegalAccessException e) {
376: LOGGER.log(Level.INFO, null, e);
377: throw new RuntimeException();
378: }
379: }
380:
381: static class PageInfoImpl extends
382: org.netbeans.modules.web.jsps.parserapi.PageInfo {
383:
384: public PageInfoImpl(/*BeanRepository beanRepository*/
385: Map taglibsMap, Map jspPrefixMapper, Map xmlPrefixMapper,
386: Map approxXmlPrefixMapper, List imports,
387: List dependants, List includePrelude, List includeCoda,
388: List pluginDcls, Set prefixes) {
389: super (taglibsMap, jspPrefixMapper, xmlPrefixMapper,
390: approxXmlPrefixMapper, imports, dependants,
391: includePrelude, includeCoda, pluginDcls, prefixes);
392: }
393:
394: private String xmlView;
395:
396: public void setXMLView(String xmlView) {
397: this .xmlView = xmlView;
398: }
399:
400: public String getXMLView() {
401: return xmlView;
402: }
403:
404: @Override
405: public String toString() {
406: StringBuilder sb = new StringBuilder();
407: sb.append(super .toString());
408: sb
409: .append(" ------- XML View (constructed from the original data structure) -----\n"); // NOI18N
410: if (xmlView == null) {
411: sb.append("no XML view\n"); // NOI18N
412: } else {
413: sb.append(getXMLView());
414: }
415: return sb.toString();
416: }
417: }
418:
419: static class BeanDataImpl implements
420: org.netbeans.modules.web.jsps.parserapi.PageInfo.BeanData {
421:
422: private final String id;
423: private final int scope;
424: private final String className;
425:
426: BeanDataImpl(String id, int scope, String className) {
427: this .id = id;
428: this .scope = scope;
429: this .className = className;
430: }
431:
432: /** Identifier of the bean in the page (variable name). */
433: public String getId() {
434: return id;
435: }
436:
437: /** Scope for this bean. Returns constants defined in {@link javax.servlet.jsp.PageContext}. */
438: public int getScope() {
439: return scope;
440: }
441:
442: /** Returns the class name for this bean. */
443: public String getClassName() {
444: return className;
445: }
446: }
447:
448: // ------ getting BeanRepository data by reflection
449: private static Field sessionBeansF, pageBeansF, appBeansF,
450: requestBeansF, beanTypesF;
451:
452: private static void initBeanRepositoryFields() {
453: if (sessionBeansF == null) {
454: try {
455: sessionBeansF = BeanRepository.class
456: .getDeclaredField("sessionBeans");
457: sessionBeansF.setAccessible(true);
458: pageBeansF = BeanRepository.class
459: .getDeclaredField("pageBeans");
460: pageBeansF.setAccessible(true);
461: appBeansF = BeanRepository.class
462: .getDeclaredField("appBeans");
463: appBeansF.setAccessible(true);
464: requestBeansF = BeanRepository.class
465: .getDeclaredField("requestBeans");
466: requestBeansF.setAccessible(true);
467: beanTypesF = BeanRepository.class
468: .getDeclaredField("beanTypes");
469: beanTypesF.setAccessible(true);
470: } catch (NoSuchFieldException e) {
471: LOGGER.log(Level.INFO, null, e);
472: }
473: }
474: }
475:
476: // ------ getting BeanRepository data by reflection
477: private static Field pluginDclsF, prefixesF, taglibsMapF,
478: jspPrefixMapperF, xmlPrefixMapperF;
479:
480: private static void initPageInfoFields() {
481: if (pluginDclsF == null) {
482: try {
483: pluginDclsF = PageInfo.class
484: .getDeclaredField("pluginDcls");
485: pluginDclsF.setAccessible(true);
486: prefixesF = PageInfo.class.getDeclaredField("prefixes");
487: prefixesF.setAccessible(true);
488: taglibsMapF = PageInfo.class
489: .getDeclaredField("taglibsMap");
490: taglibsMapF.setAccessible(true);
491: jspPrefixMapperF = PageInfo.class
492: .getDeclaredField("jspPrefixMapper");
493: jspPrefixMapperF.setAccessible(true);
494: xmlPrefixMapperF = PageInfo.class
495: .getDeclaredField("xmlPrefixMapper");
496: xmlPrefixMapperF.setAccessible(true);
497: } catch (NoSuchFieldException e) {
498: LOGGER.log(Level.INFO, null, e);
499: }
500: }
501: }
502:
503: private static Vector getPluginDclsReflect(PageInfo pageInfo) {
504: initPageInfoFields();
505: try {
506: return (Vector) pluginDclsF.get(pageInfo);
507: } catch (IllegalAccessException e) {
508: LOGGER.log(Level.INFO, null, e);
509: throw new RuntimeException();
510: }
511: }
512:
513: private static HashSet getPrefixesReflect(PageInfo pageInfo) {
514: initPageInfoFields();
515: try {
516: return (HashSet) prefixesF.get(pageInfo);
517: } catch (IllegalAccessException e) {
518: LOGGER.log(Level.INFO, null, e);
519: throw new RuntimeException();
520: }
521: }
522:
523: private static class TagFileInfoCacheRecord {
524: final long time;
525: final TagFileInfo tagFileInfo;
526:
527: public TagFileInfoCacheRecord(long time, TagFileInfo info) {
528: tagFileInfo = info;
529: this .time = time;
530: }
531: }
532:
533: /** The cache for the tag infos from tagfiles. There are stored TagInfoCacheRecord as value and
534: * the path for a tagfile as key. The informations are cached for the whole application.
535: * The cache is changed, when a jsp page is parsed and a tag file was changed.
536: */
537:
538: private static Hashtable<URL, TagFileInfoCacheRecord> tagFileInfoCache = new Hashtable<URL, TagFileInfoCacheRecord>();
539:
540: private static Map getTaglibsMapReflect(PageInfo pageInfo,
541: JspCompilationContext ctxt) {
542: initPageInfoFields();
543: try {
544: Map taglibs = (Map) taglibsMapF.get(pageInfo);
545: Iterator iter = taglibs.values().iterator();
546: TagLibraryInfo libInfo;
547: // Caching information about tag files from implicit libraries
548: while (iter.hasNext()) {
549: libInfo = (TagLibraryInfo) iter.next();
550: try {
551: if (libInfo instanceof ImplicitTagLibraryInfo) {
552: //We need the access for the files
553: Field tagFileMapF = ImplicitTagLibraryInfo.class
554: .getDeclaredField("tagFileMap");
555: tagFileMapF.setAccessible(true);
556: Hashtable tagFileMap = (Hashtable) tagFileMapF
557: .get(libInfo);
558: TagFileInfo[] tagFiles = new TagFileInfo[tagFileMap
559: .size()];
560: int index = 0;
561: //Check every file in tag library
562: Enumeration e = tagFileMap.keys();
563: while (e.hasMoreElements()) {
564: //Find the path for the file
565: String name = (String) e.nextElement();
566: String filePath = (String) tagFileMap
567: .get(name);
568:
569: URL path = ctxt.getResource(filePath);
570: File file = new File(new URI(path
571: .toExternalForm()));
572: // Is there the file in the cache?
573: if (tagFileInfoCache.containsKey(path)) {
574: TagFileInfoCacheRecord r = (TagFileInfoCacheRecord) tagFileInfoCache
575: .get(path);
576: // Is there a change in the tagfile?
577: if (r.time < file.lastModified()) {
578: tagFileInfoCache
579: .put(
580: path,
581: new TagFileInfoCacheRecord(
582: file
583: .lastModified(),
584: libInfo
585: .getTagFile(name)));
586: }
587: } else {
588: tagFileInfoCache
589: .put(
590: path,
591: new TagFileInfoCacheRecord(
592: file
593: .lastModified(),
594: libInfo
595: .getTagFile(name)));
596: }
597: //Obtain information from the cache
598: tagFiles[index++] = tagFileInfoCache
599: .get(path).tagFileInfo;
600: }
601: Field tagInfosF = ImplicitTagLibraryInfo.class
602: .getSuperclass().getDeclaredField(
603: "tagFiles");
604: tagInfosF.setAccessible(true);
605: tagInfosF.set(libInfo, tagFiles);
606: }
607: } catch (NoSuchFieldException e) {
608: LOGGER.log(Level.INFO, null, e);
609: } catch (MalformedURLException e) {
610: LOGGER.log(Level.INFO, null, e);
611: } catch (URISyntaxException e) {
612: LOGGER.log(Level.INFO, null, e);
613: }
614: }
615: return taglibs;
616: } catch (IllegalAccessException e) {
617: LOGGER.log(Level.INFO, null, e);
618: throw new RuntimeException();
619: }
620: }
621:
622: private static Map getJSPPrefixMapperReflect(PageInfo pageInfo) {
623: initPageInfoFields();
624: try {
625: return (Map) jspPrefixMapperF.get(pageInfo);
626: } catch (IllegalAccessException e) {
627: LOGGER.log(Level.INFO, null, e);
628: throw new RuntimeException();
629: }
630: }
631:
632: private static Map getXMLPrefixMapperReflect(PageInfo pageInfo) {
633: initPageInfoFields();
634: try {
635: return (Map) xmlPrefixMapperF.get(pageInfo);
636: } catch (IllegalAccessException e) {
637: LOGGER.log(Level.INFO, null, e);
638: throw new RuntimeException();
639: }
640: }
641: }
|