001: // JigsawServletContext.java
002: // $Id: JigsawServletContext.java,v 1.34 2007/02/11 10:50:01 ylafon Exp $
003: // (c) COPYRIGHT MIT and INRIA, 1998.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.jigsaw.servlet;
007:
008: import java.io.ByteArrayOutputStream;
009: import java.io.File;
010: import java.io.IOException;
011: import java.io.InputStream;
012: import java.io.PrintStream;
013: import java.io.PrintWriter;
014: import java.io.RandomAccessFile;
015:
016: import java.net.MalformedURLException;
017: import java.net.URL;
018: import java.net.URLConnection;
019:
020: import java.util.Date;
021: import java.util.Enumeration;
022: import java.util.Hashtable;
023: import java.util.Set;
024:
025: import javax.servlet.RequestDispatcher;
026: import javax.servlet.Servlet;
027: import javax.servlet.ServletContext;
028:
029: import org.w3c.util.EmptyEnumeration;
030: import org.w3c.util.ObservableProperties;
031: import org.w3c.util.PropertyMonitoring;
032:
033: import org.w3c.tools.resources.event.StructureChangedAdapter;
034: import org.w3c.tools.resources.event.StructureChangedEvent;
035:
036: import org.w3c.tools.resources.AttributeHolder;
037: import org.w3c.tools.resources.DirectoryResource;
038: import org.w3c.tools.resources.FileResource;
039: import org.w3c.tools.resources.FramedResource;
040: import org.w3c.tools.resources.InvalidResourceException;
041: import org.w3c.tools.resources.LookupResult;
042: import org.w3c.tools.resources.LookupState;
043: import org.w3c.tools.resources.ProtocolException;
044: import org.w3c.tools.resources.Resource;
045: import org.w3c.tools.resources.ResourceFrame;
046: import org.w3c.tools.resources.ResourceReference;
047: import org.w3c.tools.resources.ServerInterface;
048:
049: import org.w3c.jigsaw.frames.HTTPFrame;
050:
051: import org.w3c.jigsaw.proxy.ForwardFrame;
052: import org.w3c.jigsaw.resources.VirtualHostResource;
053: import org.w3c.jigsaw.http.httpd;
054:
055: /**
056: * @version $Revision: 1.34 $
057: * @author Benoît Mahé (bmahe@w3.org)
058: */
059: public class JigsawServletContext extends StructureChangedAdapter
060: implements ServletContext, PropertyMonitoring {
061:
062: public static final String TEMPDIR_P = "javax.servlet.context.tempdir";
063:
064: class Logger {
065: File logfile = null;
066: RandomAccessFile log = null;
067: byte msgbuf[] = null;
068: boolean closed = true;
069:
070: private final String monthnames[] = { "Jan", "Feb", "Mar",
071: "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov",
072: "Dec" };
073:
074: String getDate() {
075: Date now = new Date();
076: return (now.getDate()
077: + "/"
078: + monthnames[now.getMonth()]
079: + "/"
080: + (now.getYear() + 1900)
081: + ((now.getHours() < 10) ? (":0" + now.getHours())
082: : (":" + now.getHours()))
083: + ((now.getMinutes() < 10) ? (":0" + now
084: .getMinutes()) : (":" + now.getMinutes()))
085: + ((now.getSeconds() < 10) ? (":0" + now
086: .getSeconds()) : (":" + now.getSeconds())) + ((now
087: .getTimezoneOffset() < 0) ? " "
088: + (now.getTimezoneOffset() / 60) : " +"
089: + (now.getTimezoneOffset() / 60)));
090: }
091:
092: void log(String msg) {
093: msg = "[" + getDate() + "] " + msg + "\n";
094: try {
095: if (log == null || closed)
096: openLogFile();
097: if (log != null) {
098: int len = msg.length();
099: if (len > msgbuf.length)
100: msgbuf = new byte[len];
101: msg.getBytes(0, len, msgbuf, 0);
102: log.write(msgbuf, 0, len);
103: }
104: } catch (IOException ex) {
105: System.out.println("Can't write (" + msg
106: + ") to logfile [" + logfile + "] : "
107: + ex.getMessage());
108: }
109: }
110:
111: void log(Exception ex, String msg) {
112: log(msg + " : " + ex.getClass().getName() + " ("
113: + ex.getMessage() + ")");
114: }
115:
116: void log(Throwable throwable, String msg) {
117: ByteArrayOutputStream out = new ByteArrayOutputStream();
118: PrintWriter writer = new PrintWriter(out);
119: throwable.printStackTrace(writer);
120: writer.close();
121: String stacktrace = out.toString();
122: log(msg + " " + stacktrace);
123: }
124:
125: void openLogFile() throws IOException {
126: RandomAccessFile old = log;
127: log = new RandomAccessFile(logfile, "rw");
128: log.seek(log.length());
129: closed = false;
130: if (old != null)
131: old.close();
132: }
133:
134: void close() {
135: try {
136: if (log != null)
137: log.close();
138: closed = true;
139: } catch (IOException ex) {
140: ex.printStackTrace();
141: }
142: }
143:
144: Logger(File logfile) {
145: this .logfile = logfile;
146: this .msgbuf = new byte[128];
147: log("Servlet Logger started");
148: }
149: }
150:
151: private ResourceReference reference = null;
152:
153: private Logger logger = null;
154:
155: private ObservableProperties props = null;
156:
157: private File directory = null;
158:
159: private Hashtable attributes = null;
160:
161: protected static String logdir = "logs";
162:
163: protected static String deflogfile = "servlets";
164:
165: public boolean propertyChanged(String name) {
166: if (name.equals(ServletProps.SERVLET_LOG_FILE_P)) {
167: if (logger != null) {
168: logger.close();
169: File newlogfile = new File((String) props
170: .get(ServletProps.SERVLET_LOG_FILE_P));
171: if (newlogfile.getPath().length() < 1)
172: newlogfile = getServletLogFile();
173: logger = new Logger(newlogfile);
174: }
175: }
176: return true;
177: }
178:
179: public void resourceUnloaded(StructureChangedEvent evt) {
180: if (logger != null) {
181: logger.close();
182: }
183: }
184:
185: protected long getServletTimeout() {
186: return props.getLong(ServletProps.SERVLET_TIMEOUT, -1);
187: }
188:
189: protected int getServletInstanceMax() { // added for single thread model servlet instance pool size limitation, tk, 20.10.2001
190: return props.getInteger(ServletProps.SERVLET_INSTANCEMAX, 0);
191: }
192:
193: /**
194: * A useful utility routine that tries to guess the content-type
195: * of an object based upon its extension.
196: */
197: protected static String guessContentTypeFromName(String fname) {
198: return org.w3c.www.mime.Utils.guessContentTypeFromName(fname);
199: }
200:
201: /**
202: * ServletContext implementation - Get the MIME type for given file.
203: */
204: public String getMimeType(String filename) {
205: return guessContentTypeFromName(filename);
206: }
207:
208: public ServerInterface getServer() {
209: try {
210: Resource res = reference.lock();
211: return ((ServletDirectoryFrame) res).getServer();
212: } catch (InvalidResourceException ex) {
213: ex.printStackTrace();
214: return null;
215: } finally {
216: reference.unlock();
217: }
218: }
219:
220: public File getServletLogFile() {
221: ServerInterface server = getServer();
222: File logfile = null;
223: String file = (String) server.getProperties().getString(
224: ServletProps.SERVLET_LOG_FILE_P, null);
225: if (file != null)
226: logfile = new File(file);
227: if ((logfile != null) && (logfile.getPath().length() < 1))
228: logfile = null;
229: if (logfile == null) {
230: File root_dir = server.getRootDirectory();
231: if (root_dir == null) {
232: throw new RuntimeException("unable to build a default "
233: + "value for the servlet log file.");
234: }
235: logfile = new File(new File(root_dir, logdir), deflogfile);
236: server.getProperties().putValue(
237: ServletProps.SERVLET_LOG_FILE_P,
238: logfile.getAbsolutePath());
239: }
240: return logfile;
241: }
242:
243: /**
244: * ServletContext implementation - Lookup a given servlet.
245: * @deprecated since jsdk2.1
246: */
247:
248: public Servlet getServlet(String name) {
249: try {
250: Resource res = reference.lock();
251: return ((ServletDirectoryFrame) res).getServlet(name);
252: } catch (InvalidResourceException ex) {
253: ex.printStackTrace();
254: return null;
255: } finally {
256: reference.unlock();
257: }
258: }
259:
260: /**
261: * ServletContext implementation - Enumerate all servlets within context.
262: * @deprecated since jsdk2.1
263: */
264:
265: public Enumeration getServlets() {
266: try {
267: Resource res = reference.lock();
268: return ((ServletDirectoryFrame) res).getServlets();
269: } catch (InvalidResourceException ex) {
270: ex.printStackTrace();
271: return null;
272: } finally {
273: reference.unlock();
274: }
275: }
276:
277: /**
278: * ServletContext implementation - Enumerate all servlets names
279: * within context.
280: * @deprecated since jsdk2.1
281: */
282: public Enumeration getServletNames() {
283: try {
284: Resource res = reference.lock();
285: return ((ServletDirectoryFrame) res).getServletNames();
286: } catch (InvalidResourceException ex) {
287: ex.printStackTrace();
288: return null;
289: } finally {
290: reference.unlock();
291: }
292: }
293:
294: /**
295: * ServletContext implementation - Log a message.
296: */
297: public void log(String msg) {
298: logger.log(msg);
299: }
300:
301: /**
302: * @deprecated since jsdk2.1
303: */
304: public void log(Exception ex, String msg) {
305: logger.log(ex, msg);
306: }
307:
308: public void log(String message, Throwable throwable) {
309: logger.log(throwable, message);
310: }
311:
312: /**
313: * ServletContext implementation - Translate a piece of path.
314: * @param path the virtual path to translate
315: * @param rr_root the Root ResourceReference
316: * @param rr the target ResourceReference
317: * @return the real path
318: */
319: protected static String getRealPath(String path,
320: ResourceReference rr_root, ResourceReference rr) {
321: ResourceReference local_root = getLocalRoot(rr_root, rr);
322: try {
323: FramedResource root = (FramedResource) local_root.lock();
324: LookupState ls = new LookupState(path);
325: LookupResult lr = new LookupResult(local_root);
326: if (root.lookup(ls, lr)) {
327: ResourceReference target = lr.getTarget();
328: if (target != null) {
329: try {
330: FramedResource res = (FramedResource) target
331: .lock();
332: if (res instanceof FileResource) {
333: File file = ((FileResource) res).getFile();
334: return file.getAbsolutePath();
335: } else if (res instanceof DirectoryResource) {
336: DirectoryResource dir = (DirectoryResource) res;
337: return dir.getDirectory().getAbsolutePath();
338: //return getFilePath(dir);
339: }
340: } finally {
341: target.unlock();
342: }
343: }
344: }
345: return null;
346: } catch (InvalidResourceException ex) {
347: return null;
348: } catch (org.w3c.tools.resources.ProtocolException pex) {
349: return null;
350: } finally {
351: local_root.unlock();
352: }
353: }
354:
355: /**
356: * from Servlet 2.3, very file-oriented
357: * FIXME always returning null as of now
358: */
359: public Set getResourcePaths(String path) {
360: return null;
361: }
362:
363: /**
364: * from Servlet 2.3, very file-oriented should return a web-app container
365: * name
366: * FIXME always returning null as of now
367: */
368: public String getServletContextName() {
369: return null;
370: }
371:
372: /**
373: * ServletContext implementation - Translate a piece of path.
374: * @param path the virtual path to translate
375: * @return the real path
376: */
377: public String getRealPath(String path) {
378: ResourceReference rr_root = ((httpd) getServer())
379: .getRootReference();
380: return getRealPath(path, rr_root, reference);
381: }
382:
383: protected static String getFilePath(DirectoryResource dir) {
384: HTTPFrame frame = (HTTPFrame) dir
385: .getFrame("org.w3c.jigsaw.frames.HTTPFrame");
386: String indexes[] = frame.getIndexes();
387: if (indexes != null) {
388: for (int i = 0; i < indexes.length; i++) {
389: String index = indexes[i];
390: if (index != null && index.length() > 0) {
391: ResourceReference rr = dir.lookup(index);
392: if (rr != null) {
393: try {
394: FramedResource ri = (FramedResource) rr
395: .lock();
396: if (ri instanceof FileResource) {
397: FileResource fr = (FileResource) ri;
398: File file = fr.getFile();
399: return file.getAbsolutePath();
400: } else {
401: // we don't know
402: return null;
403: }
404: } catch (InvalidResourceException ex) {
405: } finally {
406: rr.unlock();
407: }
408: }
409: }
410: }
411: return dir.getDirectory().getAbsolutePath();
412: } else {
413: return dir.getDirectory().getAbsolutePath();
414: }
415: }
416:
417: protected static ResourceReference getLocalRoot(
418: ResourceReference rr_root, ResourceReference ref) {
419: try {
420: FramedResource root = (FramedResource) rr_root.lock();
421: if (root instanceof VirtualHostResource) {
422: //backward to the virtual host resource
423: ResourceReference rr = null;
424: ResourceReference rrp = null;
425: FramedResource res = null;
426: try {
427: res = (FramedResource) ref.lock();
428: if (res instanceof ResourceFrame) {
429: ResourceFrame fr = (ResourceFrame) res;
430: rr = fr.getResource().getResourceReference();
431: } else {
432: rr = ref;
433: }
434: } catch (InvalidResourceException ex) {
435: return rr_root;
436: } finally {
437: ref.unlock();
438: }
439:
440: while (true) {
441: try {
442: res = (FramedResource) rr.lock();
443: rrp = res.getParent();
444: if ((rrp == rr_root) || (rrp == null)) {
445: return getLocalRoot(rr, ref);
446: }
447: } catch (InvalidResourceException ex) {
448: return rr_root;
449: } finally {
450: rr.unlock();
451: }
452: rr = rrp;
453: }
454: } else {
455: try {
456: FramedResource res = (FramedResource) rr_root
457: .lock();
458: ForwardFrame ffr = (ForwardFrame) res
459: .getFrame("org.w3c.jigsaw.proxy.ForwardFrame");
460: if (ffr == null) {
461: return rr_root;
462: } else {
463: ResourceReference rr = ffr
464: .getLocalRootResource();
465: return getLocalRoot(rr, ref);
466: }
467: } catch (InvalidResourceException ex) {
468: return rr_root;
469: }
470: }
471: } catch (InvalidResourceException ex) {
472: return rr_root;
473: } finally {
474: rr_root.unlock();
475: }
476: }
477:
478: /**
479: * ServletContext implementation - Get server informations.
480: */
481:
482: public String getServerInfo() {
483: try {
484: Resource res = reference.lock();
485: return ((ServletDirectoryFrame) res).getServerInfo();
486: } catch (InvalidResourceException ex) {
487: ex.printStackTrace();
488: return null;
489: } finally {
490: reference.unlock();
491: }
492: }
493:
494: /**
495: * ServletContext implementation - Get an attribute value.
496: * We map this into the ServletWrapper attributes, without
497: * support for name clashes though.
498: * @param name The attribute name.
499: */
500:
501: public Object getAttribute(String name) {
502: Object attribute = attributes.get(name);
503: if (attribute != null) {
504: return attribute;
505: } else {
506: try {
507: Resource res = reference.lock();
508: return ((ServletDirectoryFrame) res).getAttribute(name);
509: } catch (InvalidResourceException ex) {
510: ex.printStackTrace();
511: return null;
512: } finally {
513: reference.unlock();
514: }
515: }
516: }
517:
518: public void setAttribute(String name, Object object) {
519: attributes.put(name, object);
520: }
521:
522: public void removeAttribute(String name) {
523: attributes.remove(name);
524: }
525:
526: public Enumeration getAttributeNames() {
527: return attributes.keys();
528: }
529:
530: /**
531: * Returns a <code>String</code> containing the value of the named
532: * context-wide initialization parameter, or <code>null</code> if the
533: * parameter does not exist.
534: *
535: * <p>This method can make available configuration information useful
536: * to an entire "web application". For example, it can provide a
537: * webmaster's email address or the name of a system that holds
538: * critical data.
539: *
540: * @param name a <code>String</code> containing the name of the
541: * parameter whose value is requested
542: * @return a <code>String</code> containing at least the
543: * servlet container name and version number
544: * @see ServletConfig#getInitParameter
545: */
546: public String getInitParameter(String name) {
547: // @@ not implemented @@
548: return null;
549: }
550:
551: /**
552: * Returns the names of the context's initialization parameters as an
553: * <code>Enumeration</code> of <code>String</code> objects, or an
554: * empty <code>Enumeration</code> if the context has no initialization
555: * parameters.
556: *
557: * @return an <code>Enumeration</code> of <code>String</code>
558: * objects containing the names of the context's initialization parameters
559: * @see ServletConfig#getInitParameter
560: */
561: public Enumeration getInitParameterNames() {
562: // @@ not implemented @@
563: return new EmptyEnumeration();
564: }
565:
566: private AutoReloadServletLoader loader = null;
567:
568: /**
569: * Get or create a suitable LocalServletLoader instance to load
570: * that servlet.
571: * @return A LocalServletLoader instance.
572: */
573: protected synchronized AutoReloadServletLoader getLocalServletLoader() {
574: if (loader == null) {
575: loader = new AutoReloadServletLoader(this );
576: }
577: return loader;
578: }
579:
580: protected synchronized AutoReloadServletLoader createNewLocalServletLoader(
581: boolean keepold) {
582: if ((loader != null) && keepold)
583: loader = new AutoReloadServletLoader(loader);
584: else
585: loader = new AutoReloadServletLoader(this );
586: return loader;
587: }
588:
589: public File getServletDirectory() {
590: return directory;
591: }
592:
593: //jsdk2.1
594:
595: /**
596: * Returns a RequestDispatcher object for the specified URL path if
597: * the context knows of an active source (such as a servlet, JSP page,
598: * CGI script, etc) of content for the particular path. This format of
599: * the URL path must be of the form /dir/dir/file.ext. The servlet
600: * engine is responsible for implementing whatever functionality is
601: * required to wrap the target source with an implementation of
602: * the RequestDispatcher interface.
603: * @param urlpath Path to use to look up the target server resource
604: */
605: public RequestDispatcher getRequestDispatcher(String urlpath) {
606: return JigsawRequestDispatcher.getRequestDispatcher(urlpath,
607: (httpd) getServer(), reference);
608: }
609:
610: /**
611: * Returns a {@link RequestDispatcher} object that acts
612: * as a wrapper for the named servlet.
613: *
614: * <p>Servlets (and JSP pages also) may be given names via server
615: * administration or via a web application deployment descriptor.
616: * A servlet instance can determine its name using
617: * {@link ServletConfig#getServletName}.
618: *
619: * <p>This method returns <code>null</code> if the
620: * <code>ServletContext</code>
621: * cannot return a <code>RequestDispatcher</code> for any reason.
622: *
623: * @param name a <code>String</code> specifying the name
624: * of a servlet to wrap
625: * @return a <code>RequestDispatcher</code> object
626: * that acts as a wrapper for the named servlet
627: * @see RequestDispatcher
628: * @see ServletContext#getContext
629: * @see ServletConfig#getServletName
630: */
631: public RequestDispatcher getNamedDispatcher(String name) {
632: if (name == null) {
633: throw new IllegalArgumentException("null");
634: }
635: return JigsawRequestDispatcher.getRequestDispatcher(name,
636: reference, (httpd) getServer());
637: }
638:
639: public int getMajorVersion() {
640: return 2;
641: }
642:
643: public int getMinorVersion() {
644: return 2;
645: }
646:
647: public ServletContext getContext(String uripath) {
648: if (uripath == null)
649: return null;
650: //first, find the ServletDirectoryFrame.
651: // Prepare for lookup:
652: ResourceReference rr_root = null;
653: rr_root = ((httpd) getServer()).getRootReference();
654:
655: FramedResource root = null;
656: root = ((httpd) getServer()).getRoot();
657:
658: // Do the lookup:
659: ResourceReference r_target = null;
660: try {
661: LookupState ls = new LookupState(uripath);
662: LookupResult lr = new LookupResult(rr_root);
663: root.lookup(ls, lr);
664: r_target = lr.getTarget();
665: } catch (Exception ex) {
666: r_target = null;
667: }
668: //then return its context
669: if (r_target != null) {
670: try {
671: Resource target = r_target.lock();
672: if (target instanceof FramedResource) {
673: ServletDirectoryFrame frame = (ServletDirectoryFrame) ((FramedResource) target)
674: .getFrame("org.w3c.jigsaw.servlet.ServletDirectoryFrame");
675: if (frame != null)
676: return frame.getServletContext();
677: }
678: } catch (InvalidResourceException ex) {
679: // continue
680: } finally {
681: r_target.unlock();
682: }
683: }
684: return null;
685: }
686:
687: public URL getResource(String path) throws MalformedURLException {
688: // FIXME? is it allowed?
689: File file = new File(path);
690: if (file.exists()) {
691: return new URL("file", "", file.getAbsolutePath());
692: }
693: String realpath = getRealPath(path);
694: if (realpath != null) {
695: file = new File(realpath);
696: if (file.exists()) {
697: return new URL("file", "", file.getAbsolutePath());
698: } else {
699: return null;
700: }
701: } else {
702: // it could be a virtual resource
703: // check that it exists (on server)
704: // FIXME (Virtual host)
705: return null;
706: }
707: }
708:
709: public InputStream getResourceAsStream(String path) {
710: try {
711: URL resource = getResource(path);
712: if (resource == null)
713: return null;
714: try {
715: URLConnection c = resource.openConnection();
716: return c.getInputStream();
717: } catch (IOException ex) {
718: return null;
719: }
720: } catch (MalformedURLException ex) {
721: return null;
722: }
723: }
724:
725: /**
726: * Create a new ServletContext.
727: * @param ref a ResourceReference pointing on a ServletDirectoryFrame.
728: */
729: protected JigsawServletContext(ResourceReference ref,
730: ObservableProperties props) {
731: this .reference = ref;
732: this .props = props;
733: this .attributes = new Hashtable(3);
734: this .logger = new Logger(getServletLogFile());
735: this .loader = new AutoReloadServletLoader(this );
736:
737: props.registerObserver(this );
738:
739: try {
740: Resource res = reference.lock();
741: if (!(res instanceof ServletDirectoryFrame)) {
742: throw new IllegalArgumentException(
743: "This reference is not "
744: + "pointing on a ServletDirectoryFrame.");
745: } else {
746: ServletDirectoryFrame sframe = (ServletDirectoryFrame) res;
747: FramedResource resource = (FramedResource) sframe
748: .getResource();
749: resource.addStructureChangedListener(this );
750: if (resource.definesAttribute("directory"))
751: this .directory = (File) resource.getValue(
752: "directory", null);
753: }
754: } catch (InvalidResourceException ex) {
755: throw new IllegalArgumentException(
756: "This reference is pointing on"
757: + " an Invalid ServletDirectoryFrame.");
758: } finally {
759: reference.unlock();
760: }
761: }
762:
763: }
|