001: /*
002: * ContentResolver.java February 2004
003: *
004: * Copyright (C) 2004, 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.xml.Node;
024: import simple.util.xml.Traverser;
025: import simple.util.Resolver;
026: import java.io.File;
027:
028: /**
029: * The <code>ContentResolver</code> is used to resolve a path to
030: * a specified MIME type using a pattern. The mappings used are
031: * acquired from the <code>content.xml</code> XML file, which is
032: * located using an instance of the <code>Locator</code> object.
033: * <p>
034: * This is used to implement a method, which allows a specific
035: * target to be matched to a MIME type without having to rely on
036: * the extension of the resource. For example, "index.xml" has
037: * the extenstion "xml" which would typiclly resolve to the MIME
038: * type "text/xml", however this type may not be desirable if
039: * the file was transformed to a type of "text/html" using XSLT.
040: *
041: * @author Niall Gallagher
042: *
043: * @see simple.util.Resolver
044: */
045: final class ContentResolver extends Traverser {
046:
047: /**
048: * This performs all the resolution for the target paths.
049: */
050: private Resolver list;
051:
052: /**
053: * This will determine if any patterns were loaded.
054: */
055: private int size;
056:
057: /**
058: * Constructor for the <code>ContentResolver</code>. This uses
059: * a configuration file located with the <code>Locator</code>
060: * object supplied. Once the configuration file is located it
061: * is parsed and the patterns extracted are used to resolve
062: * the target paths to the matching MIME type.
063: *
064: * @param lookup the locator used to find the configuration
065: */
066: public ContentResolver(Locator lookup) {
067: this .list = new Resolver();
068: this .init(lookup);
069: }
070:
071: /**
072: * This will attempt to acquire an XML configuration file that
073: * is used to resolve target URI paths to their MIME types. The
074: * configuration file is located using the <code>Locator</code>
075: * supplied. This will search for the configuration file using
076: * the names "Content.xml" and "content.xml".
077: *
078: * @param lookup the locator used to find the configuration
079: */
080: private void init(Locator lookup) {
081: try {
082: load(lookup);
083: } catch (Exception e) {
084: return;
085: }
086: }
087:
088: /**
089: * This <code>load</code> method attempts to load the XML file
090: * file <code>Content.xml</code> using the given locator. If
091: * the XML configuration file exists then it is used to resolve
092: * the specified MIME types from various target paths given.
093: * <p>
094: * This will attempt to load the file using the UTF-8 charset
095: * so that international characters can be used for patterns
096: * that can be used. This is compatible with the traditional
097: * Java properties format which used the ISO-8859-1 charset.
098: *
099: * @param lookup this is the locator used to discover the file
100: *
101: * @exception Exception thrown if there is an I/O problem
102: */
103: private void load(Locator lookup) throws Exception {
104: try {
105: load(lookup, "content.xml");
106: } catch (Exception e) {
107: load(lookup, "Content.xml");
108: }
109: }
110:
111: /**
112: * This will load the named file from within the given path. This
113: * is used so that a configuration file can be loaded by a locator
114: * using the specified file name. If the XML configuration file
115: * cannot be loaded this will throw an <code>Exception</code>.
116: *
117: * @param lookup this is the locator used to discover the file
118: * @param name this is the name of the configuration file loaded
119: *
120: * @exception Exception thrown if there is an I/O problem
121: */
122: private void load(Locator lookup, String name) throws Exception {
123: parse(lookup.getFile(name), "utf-8");
124: }
125:
126: /**
127: * This performs the resolution using the loaded configuration
128: * file. This uses the <code>simple.util.Resolver</code> to
129: * determine whether a wild card pattern matches a specified
130: * path. If a match is found the MIME type is returned.
131: * <p>
132: * For example, if a pattern such as <code>*.xml</code> was
133: * loaded with the value <code>text/html</code> then paths
134: * such as <code>/path/file.xml</code> would be resolved to
135: * that MIME type. For details of how the resolving is done
136: * see the <code>simple.util.Resolver</code> object.
137: *
138: * @param path this is the path that is to be resolved
139: *
140: * @return the MIME type that is resolved from the path
141: */
142: public String getContentType(String path) {
143: if (size <= 0) {
144: return null;
145: }
146: return list.resolve(path);
147: }
148:
149: /**
150: * This initializes the parser so that it can be used several
151: * times. This clears any previous tokens extracted. This
152: * ensures that when the next <code>parse(String)</code> is
153: * invoked the list of patterns used can be updated safely.
154: */
155: protected void start() {
156: list.clear();
157: }
158:
159: /**
160: * This method is used to process the resolve elements from the
161: * node object. If the element is a resolve node then this will
162: * delegate to the <code>resolve</code> method, which will
163: * save the match and type within the internal resolver object.
164: *
165: * @param node this is a node extracted from the node object
166: */
167: protected void process(Node node) {
168: String name = node.getName();
169:
170: if (name.equals("resolve")) {
171: resolve(node);
172: }
173: }
174:
175: /**
176: * This method will extract a series of match XML tags from a
177: * content block from the element node. This method requires
178: * that there is a valid match and type attribute. The BNF for
179: * the resolve element is shown below.
180: * <pre>
181: *
182: * parse = *(resolve) "<" "/" "content" ">"
183: * resolve = "<" "resolve" match type "/" ">"
184: * match = "match" "=" token
185: * type = "type" "=" token
186: *
187: * </pre>
188: * If there are no elements this will exit straight away and
189: * the resolver created will contain no data. Also, this is
190: * capable of extracting XML comments and unkown tags.
191: *
192: * @param node this is a resolve node from the node object
193: */
194: private void resolve(Node node) {
195: String match = node.getAttribute("match");
196: String type = node.getAttribute("type");
197:
198: if (match != null) {
199: list.insert(match, type);
200: }
201: }
202:
203: /**
204: * Once all the resolve elements have been evaluated this will
205: * be used to commit the configuration. This method is used to
206: * acquire the number of elements that be be sucessfully read.
207: * If the size is larger than zero the resolver is validated.
208: */
209: protected void finish() {
210: size = list.size();
211: }
212: }
|