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.io.InputStream;
047: import java.net.MalformedURLException;
048: import java.net.URL;
049: import java.util.Enumeration;
050: import java.util.HashSet;
051: import java.util.Hashtable;
052: import java.util.Set;
053: import java.util.Vector;
054: import java.util.concurrent.ConcurrentHashMap;
055: import java.util.logging.Level;
056: import java.util.logging.Logger;
057: import javax.servlet.RequestDispatcher;
058: import javax.servlet.Servlet;
059: import javax.servlet.ServletContext;
060: import javax.servlet.ServletException;
061: import javax.servlet.jsp.tagext.TagLibraryInfo;
062: import org.netbeans.modules.web.api.webmodule.WebModule;
063: import org.openide.cookies.EditorCookie;
064: import org.openide.filesystems.FileObject;
065: import org.openide.filesystems.FileUtil;
066: import org.openide.filesystems.URLMapper;
067: import org.openide.loaders.DataObject;
068: import org.openide.loaders.DataObjectNotFoundException;
069: import org.openide.text.CloneableEditorSupport;
070: import org.openide.util.NbBundle;
071:
072: /**
073: * Simple <code>ServletContext</code> implementation without
074: * HTTP-specific methods.
075: *
076: * @author Peter Rossbach (pr@webapp.de)
077: */
078:
079: public class ParserServletContext implements ServletContext {
080:
081: public static final String JSP_TAGLIBRARY_CACHE = "com.sun.jsp.taglibraryCache";
082: public static final String JSP_TAGFILE_JAR_URLS_CACHE = "com.sun.jsp.tagFileJarUrlsCache";
083:
084: private static final Logger LOGGER = Logger
085: .getLogger(ParserServletContext.class.getName());
086:
087: // ----------------------------------------------------- Instance Variables
088:
089: /**
090: * Servlet context attributes.
091: */
092: protected Hashtable<String, Object> myAttributes;
093:
094: /**
095: * The base FileObject (document root) for this context.
096: */
097: protected FileObject wmRoot;
098:
099: private final WebModuleProvider webModuleProvider;
100:
101: /** If true, takes the data from the editor; otherwise
102: * from the disk.
103: */
104: protected boolean useEditorVersion;
105:
106: // ----------------------------------------------------------- Constructors
107:
108: /**
109: * Create a new instance of this ServletContext implementation.
110: *
111: * @param wmRoot Resource base FileObject
112: * @param wm JspParserAPI.WebModule in which we are parsing the file - this is used to
113: * find the editor for objects which are open in the editor
114: */
115: public ParserServletContext(FileObject wmRoot,
116: WebModuleProvider WebModuleProvider, boolean useEditor) {
117: LOGGER.log(Level.FINE, "ParserServletContext created");
118: myAttributes = new Hashtable<String, Object>();
119: this .wmRoot = wmRoot;
120: this .webModuleProvider = WebModuleProvider;
121: this .useEditorVersion = useEditor;
122:
123: setAttribute(JSP_TAGLIBRARY_CACHE,
124: new ConcurrentHashMap<String, TagLibraryInfo>());
125: setAttribute(JSP_TAGFILE_JAR_URLS_CACHE,
126: new ConcurrentHashMap<String, URL>());
127: }
128:
129: // --------------------------------------------------------- Public Methods
130:
131: /**
132: * Return the specified context attribute, if any.
133: *
134: * @param name Name of the requested attribute
135: */
136: public Object getAttribute(String name) {
137: LOGGER.log(Level.FINE, "getAttribute({0}) = {1}", new Object[] {
138: name, myAttributes.get(name) });
139: return myAttributes.get(name);
140: }
141:
142: /**
143: * Return an enumeration of context attribute names.
144: */
145: public Enumeration<String> getAttributeNames() {
146:
147: return myAttributes.keys();
148:
149: }
150:
151: /**
152: * Return the servlet context for the specified path.
153: *
154: * @param uripath Server-relative path starting with '/'
155: */
156: public ServletContext getContext(String uripath) {
157:
158: return (null);
159:
160: }
161:
162: /**
163: * Return the specified context initialization parameter.
164: *
165: * @param name Name of the requested parameter
166: */
167: public String getInitParameter(String name) {
168:
169: return (null);
170:
171: }
172:
173: /**
174: * Return an enumeration of the names of context initialization
175: * parameters.
176: */
177: public Enumeration getInitParameterNames() {
178:
179: return (new Vector().elements());
180:
181: }
182:
183: /**
184: * Return the Servlet API major version number.
185: */
186: public int getMajorVersion() {
187:
188: return (2);
189:
190: }
191:
192: /**
193: * Return the MIME type for the specified filename.
194: *
195: * @param file Filename whose MIME type is requested
196: */
197: public String getMimeType(String file) {
198:
199: return (null);
200:
201: }
202:
203: /**
204: * Return the Servlet API minor version number.
205: */
206: public int getMinorVersion() {
207:
208: return (3);
209:
210: }
211:
212: /**
213: * Return a request dispatcher for the specified servlet name.
214: *
215: * @param name Name of the requested servlet
216: */
217: public RequestDispatcher getNamedDispatcher(String name) {
218:
219: return (null);
220:
221: }
222:
223: /** Returns a FileObject representation of the specified context-relative
224: * virtual path.
225: */
226: protected FileObject getResourceAsObject(String path) {
227: LOGGER.log(Level.FINE, "getResourceAsObject({0})", path);
228: FileObject fileObject = wmRoot.getFileObject(path);
229: WebModule webModule = webModuleProvider.getWebModule();
230: if (fileObject == null && path != null && webModule != null) {
231: int index = path.toLowerCase().indexOf("web-inf");
232: if (index > -1) {
233: String newPath = path.substring(index + 7);
234: fileObject = webModule.getWebInf().getFileObject(
235: newPath);
236: } else {
237: fileObject = webModule.getWebInf().getFileObject(path);
238: }
239: }
240: return fileObject;
241: }
242:
243: /**
244: * Return the real path for the specified context-relative
245: * virtual path.
246: *
247: * @param path The context-relative virtual path to resolve
248: */
249: public String getRealPath(String path) {
250: LOGGER.log(Level.FINE, "getRealPath({0})", path);
251: if (!path.startsWith("/")) {
252: return (null);
253: }
254: FileObject fo = getResourceAsObject(path);
255: if (fo != null) {
256: File ff = FileUtil.toFile(fo);
257: if (ff != null) {
258: return ff.getAbsolutePath();
259: }
260: }
261:
262: return null;
263: }
264:
265: /**
266: * Return a request dispatcher for the specified context-relative path.
267: *
268: * @param path Context-relative path for which to acquire a dispatcher
269: */
270: public RequestDispatcher getRequestDispatcher(String path) {
271:
272: return (null);
273:
274: }
275:
276: /**
277: * Return a URL object of a resource that is mapped to the
278: * specified context-relative path.
279: *
280: * @param path Context-relative path of the desired resource
281: *
282: * @exception MalformedURLException if the resource path is
283: * not properly formed
284: */
285: public URL getResource(String path) throws MalformedURLException {
286:
287: LOGGER.log(Level.FINE, "getResource({0})", path);
288: if (!path.startsWith("/"))
289: throw new MalformedURLException(NbBundle.getMessage(
290: ParserServletContext.class,
291: "EXC_PathMustStartWithSlash", path));
292:
293: FileObject fo = getResourceAsObject(path);
294: if (fo == null) {
295: return null;
296: }
297: return URLMapper.findURL(fo, URLMapper.EXTERNAL);
298:
299: }
300:
301: /**
302: * Return an InputStream allowing access to the resource at the
303: * specified context-relative path.
304: *
305: * @param path Context-relative path of the desired resource
306: */
307: public InputStream getResourceAsStream(String path) {
308: LOGGER.log(Level.FINE, "getResourceAsStream({0})", path);
309: // first try from the opened editor - if fails read from file
310: FileObject fo = getResourceAsObject(path);
311: if ((fo != null) && (useEditorVersion)) {
312: // reading from the editor
313: InputStream result = getEditorInputStream(fo);
314: if (result != null) {
315: return result;
316: }
317: }
318:
319: // read from the file by default
320: try {
321: URL url = getResource(path);
322: if (url == null) {
323: return null;
324: } else {
325: return url.openStream();
326: }
327: } catch (Throwable t) {
328: LOGGER.log(Level.INFO, null, t);
329: return (null);
330: }
331:
332: }
333:
334: // copied from web.core because it's the only place with this method implemented
335: // (can be easily improved using customization interface if needed)
336: /**
337: * Returns InputStream for the file open in editor or null
338: * if the file is not open.
339: */
340: private InputStream getEditorInputStream(FileObject fo) {
341: InputStream result = null;
342: EditorCookie ec = null;
343: try {
344: ec = DataObject.find(fo).getCookie(EditorCookie.class);
345: } catch (DataObjectNotFoundException e) {
346: LOGGER.log(Level.INFO, null, e);
347: }
348: if (ec != null && (ec instanceof CloneableEditorSupport)) {
349: try {
350: result = ((CloneableEditorSupport) ec).getInputStream();
351: } catch (IOException e) {
352: LOGGER.log(Level.INFO, null, e);
353: }
354: }
355: return result;
356: }
357:
358: /**
359: * Return the set of resource paths for the "directory" at the
360: * specified context path.
361: *
362: * @param path Context-relative base path
363: */
364: public Set<String> getResourcePaths(String path) {
365:
366: LOGGER.log(Level.FINE, "getResourcePaths({0})", path);
367: Set<String> thePaths = new HashSet<String>();
368: if (!path.endsWith("/"))
369: path += "/";
370: String basePath = getRealPath(path);
371: if (basePath == null)
372: return (thePaths);
373: File theBaseDir = new File(basePath);
374: if (!theBaseDir.exists() || !theBaseDir.isDirectory())
375: return (thePaths);
376: String theFiles[] = theBaseDir.list();
377: for (int i = 0; i < theFiles.length; i++) {
378: File testFile = new File(basePath + File.separator
379: + theFiles[i]);
380: if (testFile.isFile())
381: thePaths.add(path + theFiles[i]);
382: else if (testFile.isDirectory())
383: thePaths.add(path + theFiles[i] + "/");
384: }
385: return thePaths;
386:
387: }
388:
389: /**
390: * Return descriptive information about this server.
391: */
392: public String getServerInfo() {
393:
394: return ("NB.ParserServletContext/1.0");
395:
396: }
397:
398: /**
399: * Return a null reference for the specified servlet name.
400: *
401: * @param name Name of the requested servlet
402: *
403: * @deprecated This method has been deprecated with no replacement
404: */
405: public Servlet getServlet(String name) throws ServletException {
406:
407: return (null);
408:
409: }
410:
411: /**
412: * Return the name of this servlet context.
413: */
414: public String getServletContextName() {
415:
416: return (getServerInfo());
417:
418: }
419:
420: /**
421: * Return an empty enumeration of servlet names.
422: *
423: * @deprecated This method has been deprecated with no replacement
424: */
425: public Enumeration getServletNames() {
426:
427: return (new Vector().elements());
428:
429: }
430:
431: /**
432: * Return an empty enumeration of servlets.
433: *
434: * @deprecated This method has been deprecated with no replacement
435: */
436: public Enumeration getServlets() {
437:
438: return (new Vector().elements());
439:
440: }
441:
442: /**
443: * Log the specified message.
444: *
445: * @param message The message to be logged
446: */
447: public void log(String message) {
448: LOGGER.log(Level.INFO, message);
449: }
450:
451: /**
452: * Log the specified message and exception.
453: *
454: * @param exception The exception to be logged
455: * @param message The message to be logged
456: *
457: * @deprecated Use log(String,Throwable) instead
458: */
459: public void log(Exception exception, String message) {
460:
461: log(message, exception);
462:
463: }
464:
465: /**
466: * Log the specified message and exception.
467: *
468: * @param message The message to be logged
469: * @param exception The exception to be logged
470: */
471: public void log(String message, Throwable exception) {
472: LOGGER.log(Level.INFO, message);
473: LOGGER.log(Level.INFO, null, exception);
474: }
475:
476: /**
477: * Remove the specified context attribute.
478: *
479: * @param name Name of the attribute to remove
480: */
481: public void removeAttribute(String name) {
482: myAttributes.remove(name);
483:
484: }
485:
486: /**
487: * Set or replace the specified context attribute.
488: *
489: * @param name Name of the context attribute to set
490: * @param value Corresponding attribute value
491: */
492: public void setAttribute(String name, Object value) {
493: myAttributes.put(name, value);
494:
495: }
496:
497: public String getContextPath() {
498: return "";
499: }
500:
501: /**
502: * This interface delegates lifecycle of {@link WebModule} to the caller.
503: * See issue #85817 for more information.
504: */
505: public interface WebModuleProvider {
506: /**
507: * Get {@link WebModule} instance.
508: * @return {@link WebModule} instance or <code>null</code> if WebModule has already been garbage collected.
509: */
510: WebModule getWebModule();
511: }
512: }
|