alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.web.jspparser_ext;

import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspException;
import javax.xml.parsers.FactoryConfigurationError;

import org.openide.filesystems.FileChangeAdapter;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.filesystems.FileStateInvalidException;
import org.openide.ErrorManager;
import org.openide.util.NbBundle;

import org.netbeans.modules.web.jsps.parserapi.JspParserAPI;
import org.netbeans.modules.web.jsps.parserapi.Node;
import org.netbeans.modules.web.jsps.parserapi.PageInfo;
import org.netbeans.modules.web.jspparser.*;

import org.apache.jasper.Options;
import org.apache.jasper.JspCompilationContext;
import org.apache.jasper.JasperException;
import org.apache.jasper.compiler.ExtractPageData;
import org.apache.jasper.compiler.GetParseData;
import org.apache.jasper.compiler.JspRuntimeContext;
import org.apache.jasper.compiler.TldLocationsCache;
import org.netbeans.api.java.classpath.ClassPath;
import org.openide.filesystems.URLMapper;

/** Class that provides JSP parsing support for one web application. It caches 
 * some useful data on a per-webapp basis.
* * Among other things, it does the following to correctly manage the development cycle: *
    *
  • Creates the correct classloader for loading JavaBeans, tag hanlders and other classes managed by the application.
  • *
  • Caches the ServletContext (needed by the parser) corresponding to the application.
  • *
  • Listens on changes in the application and releases caches as needed.
  • *
* @author Petr Jiricka */ public class WebAppParseSupport implements WebAppParseProxy, PropertyChangeListener { private FileObject wmRoot; private OptionsImpl editorOptions; private OptionsImpl diskOptions; private ServletContext editorContext; private ServletContext diskContext; private JspRuntimeContext rctxt; private URLClassLoader waClassLoader; private URLClassLoader waContextClassLoader; /** Maps FileObject -> Long, holds timestamps for files used during classloading, * namely: all jar files containing classes, and directories+subdirectories containing unpackaged classes. */ private HashMap clRootsTimeStamps; private JspParserAPI.WebModule wm; /** The mappings field in the TldLocationsCache class. */ private static Field mappingsF; /** The mappings are cashed here. */ private Map mappings; /** This cache contains the lib (all jars), and all tld files. It's used for * checking, whether these files are not changed. */ private HashMap mappingFiles; /** ErrorManager shared by whole module (package) for logging */ /** Returns the debug level of parser. The higher the number, the more debug messages are printed out. * The debug level is specified by setting system org.netbeans.modules.jspparser.debug to a non-negative int value. * Zero means no debug messages. */ public static int getParserDebugLevel() { return Integer.getInteger("org.netbeans.modules.jspparser.debug", 0).intValue(); // NOI18N } /** Creates a new instance of WebAppParseSupport */ public WebAppParseSupport(JspParserAPI.WebModule wm) { this.wm = wm; this.wmRoot = wm.getDocumentBase(); wm.addPropertyChangeListener(this); clRootsTimeStamps = new HashMap(); reinitOptions(); mappings = null; mappingFiles = null; } public JspParserAPI.JspOpenInfo getJspOpenInfo(FileObject jspFile, boolean useEditor/*, URLClassLoader waClassLoader*/) { // PENDING - do caching for individual JSPs JspCompilationContext ctxt = createCompilationContext(jspFile, useEditor); ExtractPageData epd = new ExtractPageData(ctxt); try { return new JspParserAPI.JspOpenInfo(epd.isXMLSyntax(), epd.getEncoding()); } catch (Exception e) { if (getParserDebugLevel() > 0) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); } return getDefaultJspOpenInfo(wmRoot, jspFile); } } private JspParserAPI.JspOpenInfo getDefaultJspOpenInfo(FileObject wmRoot, FileObject jspFile) { // PENDING - we could at least look at the file extension etc. return new JspParserAPI.JspOpenInfo(false, "8859_1"); // NOI18N } synchronized void reinitOptions() { if (getParserDebugLevel() > 0) { System.out.println("[" + new Date() + "] " + //NOI18N "JSP parser reinitialized for WM " + FileUtil.toFile(wmRoot)); // NOI18N ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, "[" + new Date() + "] " + //NOI18N "JSP parser reinitialized for WM " + FileUtil.toFile(wmRoot)); // NOI18N } editorContext = new ParserServletContext(wmRoot, wm, true); diskContext = new ParserServletContext(wmRoot, wm, false); editorOptions = new OptionsImpl(editorContext); diskOptions = new OptionsImpl(diskContext); rctxt = null; // try null, but test with tag files //new JspRuntimeContext(context, options); createClassLoaders(); } private void createClassLoaders() { clRootsTimeStamps.clear(); //web.xml FileObject webxml = ContextUtil.findRelativeFileObject(wmRoot, "WEB-INF/web.xml"); if (webxml !=null ){ registerTimeStamp(webxml, false); } // libraries // WEB-INF/lib // Looking for jars in WEB-INF/lib is mainly for tests. Can a user create a lib dir in the document base // and put here a jar? ArrayList al = new ArrayList(); FileObject libDir = ContextUtil.findRelativeFileObject(wmRoot, "WEB-INF/lib"); if (libDir != null) { //registerTimeStamp(libDir, false); Enumeration libDirKids = libDir.getChildren(false); while (libDirKids.hasMoreElements()) { FileObject elem = (FileObject)libDirKids.nextElement(); registerTimeStamp(elem, false); if (elem.getExt().equals("jar")) { //NOI18N URL url = findInternalURL (elem); al.add(url); } } } URL loadingURLs[]; URL tomcatURLs[]; int rootsCount = 0; // libraries and built classes are on the execution classpath ClassPath cp = ClassPath.getClassPath(wmRoot, ClassPath.EXECUTE); if (cp != null){ FileObject [] roots = cp.getRoots(); rootsCount = roots.length; loadingURLs = new URL[al.size() + rootsCount]; tomcatURLs= new URL[al.size() + rootsCount]; for (int i = 0; i < roots.length; i++){ loadingURLs[i] = findInternalURL(roots[i]); tomcatURLs[i] = findExternalURL(roots[i]); registerTimeStamp(roots[i], false); } } else{ // XXX this is a temporary hack for the tests. It will be deled, when the tests are // rewrited for the project's infrastructure. FileObject classesDir = ContextUtil.findRelativeFileObject(wmRoot, "WEB-INF/classes"); rootsCount = (classesDir == null) ? 0 : 1; int overallSize = rootsCount + al.size(); loadingURLs = new URL[overallSize]; tomcatURLs = new URL[overallSize]; URL url; if (classesDir != null){ url = findInternalURL(classesDir); loadingURLs[0] = url; tomcatURLs[0] = url; registerTimeStamp(classesDir, false); } } for (int i = rootsCount; i < (al.size()+rootsCount); i++) { URL url = (URL)al.get(i-rootsCount); loadingURLs[i] = url; tomcatURLs[i] = url; } waClassLoader = new ParserClassLoader(loadingURLs, tomcatURLs, getClass().getClassLoader()); waContextClassLoader = new ParserClassLoader(loadingURLs, tomcatURLs, Thread.currentThread().getContextClassLoader()); if (getParserDebugLevel() > 3) { String clString; // print out webapp classloader clString = "wa class loader : " + waClassLoader; // NOI18N System.out.println(clString); ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, clString); // NOI18N // print out context class loader clString = "ctxt class loader : " + waContextClassLoader; // NOI18N System.out.println(clString); ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, clString); // NOI18N } } private URL findInternalURL(FileObject fo) { URL url = URLMapper.findURL(fo, URLMapper.INTERNAL); return url; } private URL findExternalURL(FileObject fo) { // PENDING - URLMapper.EXTERNAL does not seem to be working now, so using this workaround File f = FileUtil.toFile(fo); if ((f != null)/* && (f.isDirectory())*/) { try { return f.toURI().toURL(); } catch (MalformedURLException e) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); } } // fallback return URLMapper.findURL(fo, URLMapper.EXTERNAL); } private void registerTimeStamp(FileObject fo, boolean recursive) { try { if (fo.getURL().getProtocol().equals("jar")) // NOI18N fo = FileUtil.getArchiveFile(fo); } catch (FileStateInvalidException e){ //Nothing to do. } File f = FileUtil.toFile(fo); if (f != null) { registerTimeStamp(f, recursive); } } private void registerTimeStamp(File f, boolean recursive) { clRootsTimeStamps.put(f, new Long(f.lastModified())); if (recursive && f.isDirectory()) { File kids[] = f.listFiles( new FileFilter() { public boolean accept(File pathname) { return pathname.isDirectory(); } } ); for (int i = 0; i < kids.length; i++) { registerTimeStamp(kids[i], recursive); } } } private synchronized JspCompilationContext createCompilationContext(FileObject jspFile, boolean useEditor) { boolean isTagFile = determineIsTagFile(jspFile); String jspUri = getJSPUri(jspFile); Options options = useEditor ? editorOptions : diskOptions; ServletContext context = useEditor ? editorContext : diskContext; JspCompilationContext clctxt = null; if (isTagFile) { clctxt = new JspCompilationContext (jspUri, null, options, context, null, rctxt, null ); } else { clctxt = new JspCompilationContext (jspUri, false, options, context, null, rctxt ); } clctxt.setClassLoader(getWAClassLoader()); return clctxt; } private boolean determineIsTagFile(FileObject fo) { if (fo.getExt().startsWith("tag")) { // NOI18N - all tag, tagx and even tagf are considered tag files return true; } if (JspParserAPI.TAG_MIME_TYPE.equals(fo.getMIMEType())) { return true; } return false; } private String getJSPUri(FileObject jsp) { return ContextUtil.findRelativeContextPath(wmRoot, jsp); } // from JspCompileUtil public JspParserAPI.ParseResult analyzePage(FileObject jspFile, /*String compilationURI, */ int errorReportingMode) { // PENDING - do caching for individual JSPs JspCompilationContext ctxt = createCompilationContext(jspFile, true); /* OptionsImpl options = new OptionsImpl(jspPage); CompilationDescriptor cd = new CompilationDescriptor( JspCompileUtil.getContextRoot(jspPage.getPrimaryFile()).getFileSystem(), compilationURI); String jspResource = JspCompileUtil.getContextPath(jspPage.getPrimaryFile()); AnalyzerCompilerContext ctxt = new AnalyzerCompilerContext(jspResource, cd, options);*/ return callTomcatParser(jspFile, ctxt, waContextClassLoader, errorReportingMode); } /** * Returns the mapping of the 'global' tag library URI to the location (resource * path) of the TLD associated with that tag library. The location is * returned as a String array: * [0] The location * [1] If the location is a jar file, this is the location of the tld. */ public synchronized Map getTaglibMap(boolean useEditor) throws IOException { Options options = useEditor ? editorOptions : diskOptions; TldLocationsCache lc = options.getTldLocationsCache(); Map mappings = new HashMap(); mappings.putAll(getMappingsByReflection(lc)); return mappings; } /** Methed checks whether the files, which contains mappings (jar and tld files) * were not changed. At first obtain all jars and then all tlds. These file are * included into HashMap, which is compared with the cache. */ private synchronized boolean checkMappingsAreCurrent(){ if (mappingFiles == null) { return false; } HashMap checkedFiles = new HashMap(); // Obtain all libraries (jars). FileObject[] roots = ClassPath.getClassPath(wm.getDocumentBase(), ClassPath.EXECUTE).getRoots(); FileObject fo; File file; try{ for (int i = 0; i < roots.length; i++){ if (roots[i].getURL().getProtocol().equals("jar")) { //NOI18N fo = FileUtil.getArchiveFile(roots[i]); if (fo != null){ file = FileUtil.toFile(fo); checkedFiles.put (file, new Long(file.lastModified())); } } } } catch(org.openide.filesystems.FileStateInvalidException e){ ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); } // Obtain all tld files under WEB-INF folder FileObject webInf = ContextUtil.findRelativeFileObject(wmRoot, "WEB-INF"); if (webInf != null && webInf.isFolder()){ Enumeration en = webInf.getChildren(true); while (en.hasMoreElements()){ fo = (FileObject)en.nextElement(); if (fo.getExt().equals("tld")){ file = FileUtil.toFile(fo); checkedFiles.put (file, new Long(file.lastModified())); } } } // Compare the maps if (!checkedFiles.equals(mappingFiles)) return false; return true; } private Map getMappingsByReflection(TldLocationsCache lc) throws IOException { try { if (!checkMappingsAreCurrent()) { mappingsF = TldLocationsCache.class.getDeclaredField("mappings"); //NOI18N mappingsF.setAccessible(true); // Before new parsing, the old mappings in the TldLocationCache has to be cleared. Else there are // stored the old mappings. ((Hashtable)mappingsF.get(lc)).clear(); Thread compThread = new WebAppParseSupport.InitTldLocationCacheThread(lc); compThread.setContextClassLoader(waContextClassLoader); compThread.start(); try { compThread.join(); } catch (java.lang.InterruptedException e){ ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); } mappings = (Map)mappingsF.get(lc); //------------------------- construct the cache ----------------------------- // Obtain all files, which were parsed and store the lastchange time to the cache. java.util.Date parsEnd = new Date(); if (mappingFiles == null) mappingFiles = new HashMap(); else // clear the old cache mappingFiles.clear(); HashMap usedFile = new HashMap(); // Obtain all files which has tlds. There can be more mappings in one tld. // The value of the mapping is String[file][relative tld path] Iterator iter = mappings.values().iterator(); while (iter.hasNext()){ usedFile.put(((String[])iter.next())[0], null); } // Store the files into the cache iter = usedFile.keySet().iterator(); File file; while (iter.hasNext()){ String uri = (String)iter.next(); // usualy if the uri starts with the file, then it's a jar if (!uri.startsWith("file:")){ // NoI18N FileObject fo = ContextUtil.findRelativeFileObject(wmRoot, uri); file = FileUtil.toFile(fo); } else { uri = uri.substring(5); // remove the file: file = new File (uri); } mappingFiles.put(file, new Long(file.lastModified())); } // Add to the cache all jars, which are on the classpath. It's because // not every jar has tld, but every jar is parsed during parsing mappings. FileObject[] roots = ClassPath.getClassPath(wm.getDocumentBase(), ClassPath.EXECUTE).getRoots(); FileObject fo; try{ for (int i = 0; i < roots.length; i++){ if (roots[i].getURL().getProtocol().equals("jar")) { //NOI18N fo = FileUtil.getArchiveFile(roots[i]); if (fo != null){ file = FileUtil.toFile(fo); mappingFiles.put (file, new Long(file.lastModified())); } } } } catch(org.openide.filesystems.FileStateInvalidException e){ ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); } //------------------------- end of constructing the cache ----------------------------- } return mappings; } catch (NoSuchFieldException e) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); IOException e2 = new IOException(); e2.initCause(e); throw e2; } catch (IllegalAccessException e) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); IOException e2 = new IOException(); e2.initCause(e); throw e2; } } /** Returns the classloader to be used by the JSP parser. * This classloader loads the classes belonging to the application * from both expanded directory structures and jar files. */ public URLClassLoader getWAClassLoader() { if (!checkClassesAreCurrent()) { reinitOptions(); } return waClassLoader; } /** Checks whether the classes used by this web module have not changed since * the last time the classloader was initialized. * @return true if the classes are still the same (have not changed). */ private boolean checkClassesAreCurrent() { long timeStamp = 0; if (getParserDebugLevel() > 0) { System.out.println("[" + new Date() + "] " + //NOI18N "JSP parser classloader check started for WM " + FileUtil.toFile(wmRoot)); // NOI18N ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, "[" + new Date() + "] " + //NOI18N "JSP parser classloader check started for WM " + FileUtil.toFile(wmRoot)); // NOI18N timeStamp = System.currentTimeMillis(); } if (clRootsTimeStamps == null) { return false; } Iterator it = clRootsTimeStamps.entrySet().iterator(); while (it.hasNext()) { Map.Entry e = (Map.Entry)it.next(); File f = (File)e.getKey(); if (getParserDebugLevel() > 9) { System.out.println(" -> checking file " + f); // NOI18N ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, " -> checking file " + f); } if (!f.exists()) { return false; } if (f.lastModified() != ((Long)e.getValue()).longValue()) { return false; } } if (getParserDebugLevel() > 0) { long timeStamp2 = System.currentTimeMillis(); System.out.println("[" + new Date() + "] " + //NOI18N "check completed with result 'true', time " + (timeStamp2 - timeStamp)); } return true; } public class RRef { JspParserAPI.ParseResult result; } private JspParserAPI.ParseResult callTomcatParser(final FileObject jspFile, final JspCompilationContext ctxt, final ClassLoader contextClassLoader, final int errorReportingMode) { final RRef resultRef = new RRef(); // calling the parser in a new thread, as per the spec, we need to set the context classloader // to contain the web application classes. Jasper really relies on this Thread compThread = new Thread("JSP Parsing") { // NOI18N public void run() { try { GetParseData gpd = new GetParseData(ctxt, errorReportingMode); gpd.parse(); PageInfo nbPageInfo = gpd.getNbPageInfo(); Node.Nodes nbNodes = gpd.getNbNodes(); Throwable e = gpd.getParseException(); if (e == null) { resultRef.result = new JspParserAPI.ParseResult(nbPageInfo, nbNodes); } else { // the exceptions we may see here: // JasperException - usual // ArrayIndexOutOfBoundsException - see issue 20919 // Throwable - see issue 21169, related to Tomcat bug 7124 ErrorManager.getDefault().annotate(e, NbBundle.getMessage(WebAppParseSupport.class, "MSG_errorDuringJspParsing")); if (getParserDebugLevel() > 0) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); } JspParserAPI.ErrorDescriptor error = constructErrorDescriptor(e, wmRoot, jspFile); resultRef.result = new JspParserAPI.ParseResult(nbPageInfo, nbNodes, new JspParserAPI.ErrorDescriptor[] {error}); } } catch (ThreadDeath td) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, td); throw td; } catch (Throwable t) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t); } } }; compThread.setContextClassLoader(contextClassLoader); compThread.start(); try { compThread.join(); return resultRef.result; } catch (InterruptedException e) { JspParserAPI.ErrorDescriptor error = constructErrorDescriptor(e, wmRoot, jspFile); return new JspParserAPI.ParseResult(new JspParserAPI.ErrorDescriptor[] {error}); } /* GetParseData gpd = new GetParseData(ctxt, errorReportingMode); gpd.parse(); PageInfo nbPageInfo = gpd.getNbPageInfo(); Node.Nodes nbNodes = gpd.getNbNodes(); Throwable e = gpd.getParseException(); if (e == null) { return new JspParserAPI.ParseResult(nbPageInfo, nbNodes); } else { // the exceptions we may see here: // JasperException - usual // ArrayIndexOutOfBoundsException - see issue 20919 // Throwable - see issue 21169, related to Tomcat bug 7124 err.annotate(e, NbBundle.getMessage(WebAppParseSupport.class, "MSG_errorDuringJspParsing")); if (getParserDebugLevel() > 0) { err.notify (ErrorManager.INFORMATIONAL, e); } JspParserAPI.ErrorDescriptor error = constructErrorDescriptor(e, wmRoot, jspFile); return new JspParserAPI.ParseResult(nbPageInfo, nbNodes, new JspParserAPI.ErrorDescriptor[] {error}); } */ } private static JspParserAPI.ErrorDescriptor constructErrorDescriptor(Throwable e, FileObject wmRoot, FileObject jspPage) { JspParserAPI.ErrorDescriptor error = null; try { error = constructJakartaErrorDescriptor(wmRoot, jspPage, e); } catch (FileStateInvalidException e2) { ErrorManager.getDefault ().notify (ErrorManager.INFORMATIONAL, e2); // do nothing, error will just remain to be null } catch (IOException e2) { ErrorManager.getDefault ().notify (ErrorManager.INFORMATIONAL, e2); // do nothing, error will just remain to be null } if (error == null) { error = new JspParserAPI.ErrorDescriptor(wmRoot, jspPage, -1, -1, ContextUtil.getThrowableMessage(e, !(e instanceof JasperException)), ""); } return error; } /** Returns an ErrorDescriptor for a compilation error if the throwable was thrown by Jakarta, * otherwise returns null. */ private static JspParserAPI.ErrorDescriptor constructJakartaErrorDescriptor( FileObject wmRoot, FileObject jspPage, Throwable ex) throws IOException { // PENDING: maybe we should check all nested exceptions StringBuffer allStack = new StringBuffer(); Throwable last = ex; allStack.append(ContextUtil.getThrowableMessage(ex, true)); while (ex instanceof JasperException) { last = ex; ex = ((JasperException)ex).getRootCause(); if (ex != null) { ErrorManager.getDefault().annotate(last, ex); allStack.append(ContextUtil.getThrowableMessage(ex, true)); } } if (ex == null) ex = last; /*System.out.println("--------STACK------"); System.out.println(allStack.toString()); System.out.println("--------ENDSTACK------"); */ // now it can be JasperException, which starts with error location description String m1 = ex.getMessage(); if (m1 == null) return null; int lpar = m1.indexOf('('); if (lpar == -1) return null; int comma = m1.indexOf(',', lpar); if (comma == -1) return null; int rpar = m1.indexOf(')', comma); if (rpar == -1) return null; String line = m1.substring(lpar + 1, comma).trim(); String col = m1.substring(comma + 1, rpar).trim(); String fileName = m1.substring(0, lpar); // now cnstruct the FileObject using this file name and the web module root File file = FileUtil.toFile(wmRoot); FileObject errorFile = jspPage; // a sensible default fileName = new File(fileName).getCanonicalPath(); String wmFileName = file.getCanonicalPath(); if (fileName.startsWith(wmFileName)) { String errorRes = fileName.substring(wmFileName.length()); errorRes = errorRes.replace(File.separatorChar, '/'); if (errorRes.startsWith("/")) // NOI18N errorRes = errorRes.substring(1); FileObject errorTemp = ContextUtil.findRelativeFileObject(wmRoot, errorRes); if (errorTemp != null) errorFile = errorTemp; } // now construct the ErrorDescriptor try { String errContextPath = ContextUtil.findRelativeContextPath(wmRoot, errorFile); String errorMessage = errContextPath + " [" + line + ";" + col + "] " + m1.substring(rpar + 1).trim(); return new JspParserAPI.ErrorDescriptor( wmRoot, errorFile, Integer.parseInt(line), Integer.parseInt(col), errorMessage, ""); // NOI18N // pending - should also include a line of code } catch (NumberFormatException e) { return null; } } // IMPLEMENTATION OF PropertyChangeListener /** Handes the event of property change of libraries used by the web module. * Reinitializes the classloader and other stuff. */ public void propertyChange(java.beans.PropertyChangeEvent evt) { String propName = evt.getPropertyName(); if (JspParserAPI.WebModule.PROP_LIBRARIES.equals(propName) || JspParserAPI.WebModule.PROP_PACKAGE_ROOTS.equals(propName)) { reinitOptions(); } } /* class WAFileChangeListener extends FileChangeAdapter { PENDING - listening WAFileChangeListener() { } }*/ /** This classloader does some security stuff, but equally importantly, it does one horrible hack, * explained in the constructor Javadoc. */ public static class ParserClassLoader extends URLClassLoader { private static final RuntimePermission GET_CL_PERM = new RuntimePermission("getClassLoader"); private URL[] tomcatURLs; /** This constructor and the getURLs() method is one horrible hack. On the one hand, we want to give * Tomcat a JarURLConnection when it attempts to load classes from jars, on the other hand * we don't want this classloader to load classes using JarURLConnection, as that's buggy. * We want it to load classes using internal nb: protocols. So the getURLs() method * returns an "external" list of URLs for Tomcat, while internally, the classloader uses * an "internal" list of URLs. */ public ParserClassLoader(URL[] classLoadingURLs, URL[] tomcatURLs, ClassLoader parent) { super(classLoadingURLs, parent); this.tomcatURLs = tomcatURLs; } /** See the constructor for explanation of what thie method does. */ public URL[] getURLs() { return tomcatURLs; } protected PermissionCollection getPermissions(CodeSource codesource) { PermissionCollection perms = super.getPermissions(codesource); perms.add(GET_CL_PERM); return perms; } public String toString() { StringBuffer sb = new StringBuffer(); sb.append(super.toString()); sb.append(", parent : "); // NOI18N sb.append(getParent().toString()); return sb.toString(); } } private static class InitTldLocationCacheThread extends Thread{ private TldLocationsCache cache; InitTldLocationCacheThread (TldLocationsCache lc){ super ("Init TldLocationCache"); // NOI18N cache = lc; } public void run() { try { Field initialized= TldLocationsCache.class.getDeclaredField("initialized"); // NOI18N initialized.setAccessible(true); initialized.setBoolean(cache, false); cache.getLocation(""); } catch (JasperException e) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); } catch (NoSuchFieldException e) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); } catch (IllegalAccessException e) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); } } } }
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.