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.netbeans.modules.web.jspparser;
043:
044: import java.io.File;
045: import java.io.IOException;
046: import java.lang.reflect.Constructor;
047: import java.lang.reflect.InvocationTargetException;
048: import java.net.MalformedURLException;
049: import java.net.URL;
050: import java.net.URLClassLoader;
051: import java.security.AllPermission;
052: import java.security.CodeSource;
053: import java.security.PermissionCollection;
054: import java.util.Map;
055: import java.util.WeakHashMap;
056: import java.util.logging.Level;
057: import java.util.logging.Logger;
058: import org.netbeans.modules.web.api.webmodule.WebModule;
059: import org.netbeans.modules.web.jsps.parserapi.TldChangeListener;
060: import org.netbeans.modules.web.jsps.parserapi.JspParserAPI;
061:
062: import org.openide.filesystems.FileObject;
063: import org.openide.modules.InstalledFileLocator;
064: import org.openide.util.NbBundle;
065:
066: // PENDING - need to call reinitOptions when something changes (taglib, jar, web.xml)
067: // PENDING - separate to two classes, have a per-application instance of one of them
068:
069: /**
070: * @author Petr Jiricka
071: */
072: public class JspParserImpl implements JspParserAPI {
073:
074: // @GuardedBy(this)
075: final Map<WebModule, WebAppParseProxy> parseSupports = new WeakHashMap<WebModule, WebAppParseProxy>();
076: private final TldChangeSupport tldChangeSupport;
077:
078: private static final Logger LOGGER = Logger
079: .getLogger(JspParserImpl.class.getName());
080: private static Constructor webAppParserImplConstructor;
081:
082: private static final JspParserAPI.JspOpenInfo DEFAULT_OPENINFO = new JspParserAPI.JspOpenInfo(
083: false, "ISO-8859-1"); // NOI18N
084:
085: /** Constructs a new Parser API implementation.
086: */
087: public JspParserImpl() {
088: // PENDING - we are preventing the garbage collection of
089: // Project-s and FileObject-s (wmRoots)
090: tldChangeSupport = new TldChangeSupport(this );
091: }
092:
093: private static void initReflection() {
094: if (webAppParserImplConstructor == null) {
095: File[] files = new File[5];
096: files[0] = InstalledFileLocator.getDefault().locate(
097: "ant/lib/ant.jar", null, false); // NOI18N
098: files[1] = InstalledFileLocator.getDefault().locate(
099: "modules/ext/glassfish-jspparser-2.0.jar", null,
100: false); // NOI18N
101: //files[2] = InstalledFileLocator.getDefault().locate("modules/ext/glassfish-logging.jar", null, false); // NOI18N
102: files[2] = InstalledFileLocator.getDefault().locate(
103: "modules/ext/jsp-parser-ext.jar", null, false); // NOI18N
104: files[3] = InstalledFileLocator.getDefault().locate(
105: "modules/ext/servlet2.5-jsp2.1-api.jar", null,
106: false); // NOI18N
107: //Glassfish V2
108: files[4] = InstalledFileLocator.getDefault().locate(
109: "ant/lib/ant-launcher.jar", null, false); // NOI18N
110:
111: try {
112: URL[] urls = new URL[files.length];
113: for (int i = 0; i < files.length; i++) {
114: urls[i] = files[i].toURI().toURL();
115: }
116: ExtClassLoader urlCL = new ExtClassLoader(urls,
117: JspParserImpl.class.getClassLoader());
118: Class<?> cl = urlCL
119: .loadClass("org.netbeans.modules.web.jspparser_ext.WebAppParseSupport"); // NOI18N
120: webAppParserImplConstructor = cl
121: .getDeclaredConstructor(new Class[] {
122: JspParserImpl.class, WebModule.class });
123: } catch (NoSuchMethodException e) {
124: LOGGER.log(Level.INFO, null, e);
125: } catch (MalformedURLException e) {
126: LOGGER.log(Level.INFO, null, e);
127: } catch (ClassNotFoundException e) {
128: LOGGER.log(Level.INFO, null, e);
129: }
130: }
131: }
132:
133: public JspParserAPI.JspOpenInfo getJspOpenInfo(FileObject jspFile,
134: WebModule wm, boolean useEditor) {
135: //try to fast create openinfo
136:
137: //detects encoding even if there is not webmodule (null) or deployment descriptor doesn't exist
138: FastOpenInfoParser fastOIP = FastOpenInfoParser.get(wm);
139: if (fastOIP != null) {
140: JspParserAPI.JspOpenInfo jspOI = fastOIP.getJspOpenInfo(
141: jspFile, useEditor);
142: if (jspOI != null) {
143: return jspOI;
144: }
145: }
146:
147: //no encoding found in the file or the deployment descriptor contains encoding declarations
148: if (wm != null) {
149: FileObject wmRoot = wm.getDocumentBase();
150: if (wmRoot != null) {
151: WebAppParseProxy pp = getParseProxy(wm);
152: if (pp != null) {
153: return pp.getJspOpenInfo(jspFile, useEditor);
154: }
155: }
156: }
157: return DEFAULT_OPENINFO;
158: }
159:
160: public JspParserAPI.ParseResult analyzePage(FileObject jspFile,
161: WebModule wm, int errorReportingMode) {
162: if (wm == null) {
163: return getNoWebModuleResult(jspFile, null);
164: }
165: FileObject wmRoot = wm.getDocumentBase();
166: if (wmRoot == null) {
167: return getNoWebModuleResult(jspFile, wm);
168: }
169: WebAppParseProxy pp = getParseProxy(wm);
170: if (pp == null) {
171: return getNoWebModuleResult(jspFile, wm);
172: }
173: return pp.analyzePage(jspFile, errorReportingMode);
174: }
175:
176: /**
177: * Returns the mapping of the 'global' tag library URI to the location (resource
178: * path) of the TLD associated with that tag library.
179: * @param wmRoot the web module for which to return the map
180: * @return Map which maps global tag library URI to the location
181: * (resource path) of its tld. The location is
182: * returned as a String array:
183: * [0] The location
184: * [1] If the location is a jar file, this is the location of the tld.
185: */
186: public Map<String, String[]> getTaglibMap(WebModule wm)
187: throws IOException {
188: FileObject wmRoot = wm.getDocumentBase();
189: if (wmRoot == null) {
190: throw new IOException();
191: }
192: WebAppParseProxy pp = getParseProxy(wm);
193: return pp.getTaglibMap(true);
194: }
195:
196: private synchronized WebAppParseProxy getParseProxy(WebModule wm) {
197: WebAppParseProxy pp = parseSupports.get(wm);
198: // #67785 - the document root fileobject has to be valid
199: FileObject wmRoot = wm.getDocumentBase();
200: if (!wmRoot.isValid()) {
201: pp = null;
202: }
203: if (pp == null) {
204: pp = createParseProxy(wm);
205: parseSupports.put(wm, pp);
206: }
207: return pp;
208: }
209:
210: private WebAppParseProxy createParseProxy(WebModule wm) {
211: // PENDING - do caching for individual JSPs
212: try {
213: initReflection();
214: return (WebAppParseProxy) webAppParserImplConstructor
215: .newInstance(new Object[] { this , wm });
216: } catch (IllegalAccessException e) {
217: LOGGER.log(Level.INFO, null, e);
218: } catch (InstantiationException e) {
219: LOGGER.log(Level.INFO, null, e);
220: } catch (InvocationTargetException e) {
221: LOGGER.log(Level.INFO, null, e);
222: }
223: return null;
224: }
225:
226: public URLClassLoader getModuleClassLoader(WebModule wm) {
227: WebAppParseProxy pp = getParseProxy(wm);
228: return pp.getWAClassLoader();
229: }
230:
231: private JspParserAPI.ParseResult getNoWebModuleResult(
232: FileObject jspFile, WebModule wm) {
233: JspParserAPI.ErrorDescriptor error = new JspParserAPI.ErrorDescriptor(
234: null, jspFile, -1, -1, NbBundle.getMessage(
235: JspParserImpl.class, "MSG_webModuleNotFound",
236: jspFile.getNameExt()), ""); // NOI18N
237: return new JspParserAPI.ParseResult(
238: new JspParserAPI.ErrorDescriptor[] { error });
239: }
240:
241: public void addTldChangeListener(TldChangeListener listener) {
242: tldChangeSupport.addTldChangeListener(listener);
243: }
244:
245: public void removeTldChangeListener(TldChangeListener listener) {
246: tldChangeSupport.removeTldChangeListener(listener);
247: }
248:
249: public void fireChange(WebModule webModule) {
250: tldChangeSupport.fireChange(webModule);
251: }
252:
253: private static class ExtClassLoader extends URLClassLoader {
254:
255: private static final AllPermission ALL_PERM = new AllPermission();
256:
257: public ExtClassLoader(URL[] classLoadingURLs, ClassLoader parent) {
258: super (classLoadingURLs, parent);
259: }
260:
261: @Override
262: protected PermissionCollection getPermissions(
263: CodeSource codesource) {
264: PermissionCollection perms = super
265: .getPermissions(codesource);
266: perms.add(ALL_PERM);
267: return perms;
268: }
269:
270: @Override
271: protected synchronized Class<?> loadClass(String name,
272: boolean resolve) throws ClassNotFoundException {
273: // this is because debugger adds ant on cp but this classloader needs ant as well
274: // - so let this class loader find the class
275: if (name.startsWith("org.apache.tools.ant.")) { // NOI18N
276: Class<?> clazz = findClass(name);
277: return clazz;
278: }
279: return super.loadClass(name, resolve);
280: }
281: }
282: }
|