001: /*
002: * FileContext.java March 2002
003: *
004: * Copyright (C) 2002, Niall Gallagher <niallg@users.sf.net>
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: * GNU Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General
016: * Public License along with this library; if not, write to the
017: * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
018: * Boston, MA 02111-1307 USA
019: */
020:
021: package simple.http.serve;
022:
023: import simple.util.FileProperties;
024: import simple.util.net.Path;
025: import java.util.Properties;
026: import java.io.IOException;
027: import java.util.Locale;
028: import java.io.File;
029:
030: /**
031: * The <code>FileContext</code> provides an implementation of the
032: * <code>Context</code> object that provides a direct mapping from
033: * a request URI as defined in RFC 2616 to an OS specific target.
034: * This uses a <code>File</code> object to define the mapping
035: * for the request URI paths. Using a <code>File</code> object
036: * allows the <code>FileContext</code> to be easily used with both
037: * DOS and UNIX systems.
038: * <p>
039: * This <code>Indexer</code> implementation uses an MIME database
040: * to obtain mappings for the <code>getContentType</code> method.
041: * The file used is "Content.properties", which is packaged within
042: * <code>simple.http.serve</code>. This determines the MIME type
043: * of the request URI by matching file extension of the resource
044: * with the MIME type as defined in the "Content.properties" file.
045: * The mappings in the "Content.properties" file can be overridden
046: * by any XML file named "Content.xml" within reach of the
047: * <code>Locator</code> object, this configuration file requires
048: * the mappings to be in the form of wild card patterns.
049: * <code><pre>
050: *
051: * <?xml version="1.0" encoding="UTF-8"?>
052: * <content>
053: * <resolve match="*.jpg" type="image/jpeg">
054: * <resolve match="/gif/*" type="image/gif">
055: * </content>
056: *
057: * </pre></code>
058: * For example, taking the XML configuration file described above,
059: * this will match all files ending with the ".jpg" extenstion to
060: * the MIME type "image/jpeg". Also, all files within the "/gif/"
061: * folder will be considered GIF images with a MIME type of
062: * "image/gif". By default most of the common file extensions
063: * already have mappings, however overriding these can be useful.
064: *
065: * @author Niall Gallagher
066: *
067: * @see simple.http.serve.FileIndexer
068: */
069: public class FileContext implements Context {
070:
071: /**
072: * This is used to extract any user specified MIME types.
073: */
074: protected FileIndexer indexer;
075:
076: /**
077: * This is used to locate the configuration information.
078: */
079: protected Locator locator;
080:
081: /**
082: * This is the format instance used by this instance.
083: */
084: protected Format format;
085:
086: /**
087: * This will be used to fetch the real OS system paths.
088: */
089: protected File base;
090:
091: /**
092: * Constructor for creating an instance that operates from
093: * the given current working path. This instance will use
094: * the current path to translate the HTTP request URIs
095: * into the OS specific path. This will load configuration
096: * files from the current working directory.
097: */
098: public FileContext() {
099: this (new File("."));
100: }
101:
102: /**
103: * Constructor for creating an instance that operates from
104: * the given OS specific base path. This instance will use
105: * the given base path to translate the HTTP request URIs
106: * into the OS specific path. This will load configuration
107: * files from the specified directory path.
108: *
109: * @param base this is the OS specific base path for this
110: */
111: public FileContext(File base) {
112: this (base, base);
113: }
114:
115: /**
116: * Constructor for creating an instance that operates from
117: * the given OS specific base path. This instance will use
118: * the given base path to translate the HTTP request URIs
119: * into the OS specific path. This allows configuration
120: * files to be loaded from the file directory provided.
121: *
122: * @param base this is the OS specific base path for this
123: * @param path this is the path used to load configuration
124: */
125: public FileContext(File base, File path) {
126: this (base, new File[] { path });
127: }
128:
129: /**
130: * Constructor for creating an instance that operates from
131: * the given OS specific base path. This instance will use
132: * the given base path to translate the HTTP request URIs
133: * into the OS specific path. This allows configuration
134: * files to be loaded from the file range provided.
135: *
136: * @param base this is the OS specific base path for this
137: * @param list this path list used to load configuration
138: */
139: public FileContext(File base, File[] list) {
140: this (base, new FileLocator(list));
141: }
142:
143: /**
144: * Constructor for creating an instance that operates from
145: * the given OS specific base path. This instance will use
146: * the given base path to translate the HTTP request URIs
147: * into the OS specific path. This uses the locator object
148: * provided, which can be used to acquire configuration.
149: *
150: * @param base this is the OS specific base path for this
151: * @param locator this is the configuration file locator
152: */
153: public FileContext(File base, Locator locator) {
154: this .indexer = new FileIndexer(locator, base);
155: this .format = FormatFactory.getInstance();
156: this .locator = locator;
157: this .base = base;
158: }
159:
160: /**
161: * This is used to retrieve the base path of the context. The
162: * base path of the context is that path that that this will
163: * retrieve system information from. This represents a base
164: * that the request URI paths are served from on the system.
165: * For instance a base of "c:\path" would translate a URI
166: * path of "/index.html" into "c:\path\index.html". Every
167: * resource request must be relative to the context path
168: * this allows the <code>FileEngine</code> to map the URIs
169: * onto the specific OS. The base path is the OS file system
170: * specific path. So on UNIX it could be "/home/user/" and
171: * on a DOS system it could be "c:\web\html" for example.
172: *
173: * @return this returns the base path of the context
174: */
175: public String getBasePath() {
176: return base.getAbsolutePath();
177: }
178:
179: /**
180: * This is used to translate the HTTP request URI into the OS
181: * specific path that it represents. This will convert the
182: * URI to a format that the system can use and also represents
183: * the resource path on that system. So if for example the
184: * context path was "c:\path" on a DOS system and the HTTP URI
185: * given was "/index.html" this returns "c:\path\index.html".
186: * If a UNIX system was running the VM and the context base
187: * was for example "/home/" then this would return the UNIX
188: * path "/home/index.html" for the same request URI.
189: *
190: * @param target this is the HTTP request URI path that is to
191: * be translated into the OS specific path
192: *
193: * @return this returns the OS specific path name for the
194: * translate request URI
195: */
196: public String getRealPath(String target) {
197: return getIndex(target).getRealPath();
198: }
199:
200: /**
201: * This is used to translate the HTTP request URI into the URI
202: * path normalized and without query or parameter parts. This
203: * is used so that the resource requested by the client can be
204: * discovered. For example this will convert the HTTP request
205: * URI "http://hostname/bin;param=value/../index.html?query"
206: * into the relative URI path /index.html. This is useful if
207: * a logging mechanism requires the name of the resource that
208: * was requested, it can also be used help find the resource.
209: *
210: * @param target this is the HTTP request URI that is to be
211: * converted into a normalized relative URI path
212: *
213: * @return the HTTP request URI as a normalized relative path
214: */
215: public String getRequestPath(String target) {
216: return getIndex(target).getRequestPath();
217: }
218:
219: /**
220: * This is used to translate the HTTP request URI into the
221: * <code>File</code> object that it represents. This will convert
222: * the URI to a format that the system can use and then create
223: * the <code>File</code> object for that path. So if for example
224: * the context path was "c:\path" on a DOS system and the HTTP
225: * URI given was "/index.html" this returns the <code>File</code>
226: * "c:\path\index.html". This is basically for convenience as the
227: * same could be achieved using the <code>getRealPath</code> and
228: * then creating the <code>File</code> from that OS specific path.
229: *
230: * @param target this is the HTTP request URI path that is used
231: * to retrieve the <code>File</code> object
232: *
233: * @return returns the <code>File</code> for the given path
234: */
235: public File getFile(String target) {
236: return getIndex(target).getFile();
237: }
238:
239: /**
240: * This is used to translate the HTTP request URI into the
241: * <code>File</code> object that it represent the parent directory
242: * of the URI. This will convert the URI to a format that the host
243: * system can use and then create the <code>File</code> object for
244: * that path. So if for example the context path was "c:\path" on
245: * a DOS system and the HTTP URI given was "/index.html" this
246: * returns the <code>File</code> "c:\path\". This is basically
247: * for convenience as the same could be achieved using the file
248: * retrieved from <code>getFile</code> and acquiring the parent.
249: *
250: * @param target this is the HTTP request URI path that is used
251: * to retrieve the <code>File</code> object
252: *
253: * @return returns the <code>File</code> for the directory
254: */
255: public File getDirectory(String target) {
256: return getIndex(target).getDirectory();
257: }
258:
259: /**
260: * This is used to translate the HTTP request URI into the
261: * <code>Path</code> object that it represents. This enables the
262: * HTTP request URI to be examined thoroughly an allows various
263: * other files to be examined relative to it. For example if the
264: * URI referenced a path "/usr/bin/file" and some resource
265: * in the same directory is required then the <code>Path</code>
266: * can be used to acquire the relative path. This is useful if
267: * links within a HTML page are to be dynamically generated. The
268: * <code>Path.getRelative</code> provides this functionality.
269: *
270: * @param target this is the HTTP request URI path that is used
271: * to retrieve the <code>Path</code> object
272: *
273: * @return returns the <code>Path</code> for the given path
274: */
275: public Path getPath(String target) {
276: return getIndex(target).getPath();
277: }
278:
279: /**
280: * This will parse the HTTP request URI specified and return the
281: * <code>Locale</code> for that resource. The <code>Locale</code>
282: * is extracted from the target by examining the path segment of
283: * the HTTP request URI. The path segment is the abs_path token
284: * defined in RFC 2396. It is extracted from a second extension
285: * in the file name. So for example if the HTTP request URI was
286: * "http://some.host/usr;param=value/index.en_US.html" then the
287: * file name "index.en_US.html" would have the second file
288: * extension en_US converted into a <code>Locale</code>. This
289: * will not interfere if the file name was "compressed.tar.gz",
290: * it will simply ignore the "tar" second file extension and
291: * return <code>Locale.getDefault</code>.
292: *
293: * @param target the request URI to be parsed for its locale
294: *
295: * @return this will return the locale for the specified URI
296: */
297: public Locale getLocale(String target) {
298: return getIndex(target).getLocale();
299: }
300:
301: /**
302: * This method will extract the type attribute of this URI. The
303: * MIME type of the request URI is extracted from the name of the
304: * target. The name for the <code>Context</code> is the last path
305: * segment in the token defined by RFC 2396 as path_segments. So
306: * for example if the target was "some.host:8080/bin/index.html"
307: * then the name for that resource would be "index.html". Once
308: * the name has been extracted the MIME is defined by the file
309: * extension, which for the example is text/html. The MIME type
310: * mappings can be directly specified in a configuration file
311: * named either "Content.xml" or "content.xml".
312: *
313: * @param target the request URI to be parsed for its type
314: *
315: * @return the type of the given request URI path refers to
316: */
317: public String getContentType(String target) {
318: return getIndex(target).getContentType();
319: }
320:
321: /**
322: * This will parse and return the file name that this request URI
323: * references. The name for the <code>Context</code> is the last
324: * path segment is the token defined by RFC 2396 as path_segments.
325: * So for example if the target was "some.host:8080/home/user/"
326: * then the name for that resource would be "user". If the path
327: * references the root path "/" then null should be returned.
328: *
329: * @param target the request URI to be parsed for its name
330: *
331: * @return this will return the name that this references
332: */
333: public String getName(String target) {
334: return getIndex(target).getName();
335: }
336:
337: /**
338: * This is an all in one method that allows all the information
339: * on the target URI to be gathered at once. The motivation for
340: * this method is primarily convenience. However it is also used
341: * to increase the performance of the <code>FileEngine</code>
342: * when the <code>Context</code> implementation is synchronized.
343: * This will enable the <code>FileEngine</code> to gather the
344: * information on the target by acquiring the lock for the object
345: * instance only once.
346: *
347: * @param target this is the request URI that is to be parsed
348: */
349: public Index getIndex(String target) {
350: return indexer.getIndex(target);
351: }
352:
353: /**
354: * This retrieves a <code>Content</code> instance that wraps the
355: * specified resource. This returns a <code>Content</code> instance
356: * that transfers the contents of the referenced file in one
357: * kilobyte chunks. This does not cache the file, however if the
358: * files need to be cached the <code>FileContentFactory</code> can
359: * be used to act as a hot spot cache for heavly accessed files.
360: *
361: * @param target this is the request URI that identifies the file
362: *
363: * @throws IOException this is thrown if the file resource does
364: * not exist or cannot be accessed
365: */
366: public Content getContent(String target) throws IOException {
367: return new StreamContent(this , target);
368: }
369:
370: /**
371: * This provides a convenient way for an XML configuration file
372: * to be loaded. This resolves the target URI to a relative file
373: * within the context to be the same as the <code>getFile</code>
374: * method would return. Once the file has been acquired the Java
375: * properties file is loaded, each time, there is no caching of
376: * the loaded properties. This ensures that changes to a loaded
377: * object does not affect other users of the properties file.
378: *
379: * @param target the request URI that refers to the properties
380: *
381: * @return returns a populated <code>Properties</code> object
382: * using the specified Java properties file
383: *
384: * @throws IOException this is thrown if the resource does not
385: * exist or cannot be accessed
386: */
387: public Properties getProperties(String target) throws IOException {
388: return new FileProperties(getFile(target));
389: }
390:
391: /**
392: * Each <code>Context</code> must supply a <code>Locator</code> to
393: * enable the system to locate configuration information and other
394: * resources that reside outside the context path. This is useful
395: * when there are Java properties and XML configuration files
396: * required by objects interacting with a <code>Context</code>.
397: * The <code>Locator</code> employs a search to locate resources,
398: * which are identified either by name or using aliases.
399: *
400: * @return this returns the locator used by this context object
401: */
402: public Locator getLocator() {
403: return locator;
404: }
405:
406: /**
407: * Each <code>Context</code> object must be coupled with an instance
408: * of the <code>Format</code> object. This is required because each
409: * <code>FileEngine</code> needs to serve the directory listing and
410: * the error messages in a consistent format. The resources of the
411: * instances can thus be pooled by comparing the equality of the
412: * various <code>Context</code> objects. When there is an object
413: * that requires a <code>FileEngine</code> it can create an instance
414: * of the <code>Context</code> and using the static factory method
415: * <code>FileEngine.getInstance</code> with the context object there
416: * is a search for an active instance of the <code>FileEngine</code>.
417: * If one is found that uses a similar context object then it is
418: * returned to the caller. This enables instances and thus resources
419: * to be shared transparently.
420: *
421: * @return this returns the format used with this context object
422: */
423: public Format getFormat() {
424: return format;
425: }
426: }
|