001: /*
002: * ResourceLocator.java
003: *
004: * Created on 21. Januar 2003, 21:33
005: */
006:
007: package org.jzonic.jlo.reader;
008:
009: import java.io.*;
010: import java.net.URL;
011: import java.util.StringTokenizer;
012: import java.util.Vector;
013:
014: /**
015: * Adopted from <a href="http://www.onjava.com/pub/a/onjava/excerpt/jebp_3/index1.html?page=3">Servlet Best Practices, Part 1</a>
016: *
017: * A class to locate resources, retrieve their contents, and determine their
018: * last modified time. To find the resource the class searches the CLASSPATH
019: * first, then Resource.class.getResource("/" + name). If the Resource finds
020: * a "file:" URL, the file path will be treated as a file. Otherwise, the
021: * path is treated as a URL and has limited last modified info.
022: *
023: * @author Andreas Mecky <andreas.mecky@jzonic.org>
024: * @author Terry Dye <terry.dye@jzonic.org>
025: */
026: public class ResourceLocator implements Serializable {
027:
028: private String myName;
029: private File myFile;
030: private URL myUrl;
031:
032: /** Creates a new instance of ResourceLocator */
033: public ResourceLocator() {
034: }
035:
036: public ResourceLocator(String name) throws IOException {
037: myName = name;
038: SecurityException exception = null;
039:
040: try {
041: // Search using the CLASSPATH. If found, "file" is set and the call
042: // returns true. A SecurityException might bubble up.
043: if (tryClasspath(name)) {
044: return;
045: }
046: } catch (SecurityException e) {
047: exception = e; // Save for later.
048: }
049:
050: try {
051: // Search using the classloader getResource( ). If found as a file,
052: // "file" is set; if found as a URL, "url" is set.
053: if (tryLoader(name)) {
054: return;
055: }
056: } catch (SecurityException e) {
057: exception = e; // Save for later.
058: }
059:
060: // If you get here, something went wrong. Report the exception.
061: String msg = "";
062: if (exception != null) {
063: msg = ": " + exception;
064: }
065:
066: throw new IOException(
067: "Resource <"
068: + name
069: + "> could not be found in "
070: + "the CLASSPATH ("
071: + System.getProperty("java.class.path")
072: + "), nor could it be located by the classloader responsible for the "
073: + "web application (WEB-INF/classes)" + msg);
074: }
075:
076: /**
077: * Method findResource.
078: * @param fileName
079: * @return InputStream
080: */
081: public InputStream findResource(String fileName) {
082: if (fileName == null) {
083: return null;
084: }
085: return getClass().getClassLoader()
086: .getResourceAsStream(fileName);
087: }
088:
089: /**
090: * Returns the resource name, as passed to the constructor
091: */
092: public String getName() {
093: return myName;
094: }
095:
096: /**
097: * Returns an input stream to read the resource contents
098: */
099: public InputStream getInputStream() throws IOException {
100: if (myFile != null) {
101: return new BufferedInputStream(new FileInputStream(myFile));
102: } else if (myUrl != null) {
103: return new BufferedInputStream(myUrl.openStream());
104: }
105: return null;
106: }
107:
108: /**
109: * Returns when the resource was last modified. If the resource
110: * was found using a URL, this method will work only if the URL
111: * connection supports last modified information. If there's no
112: * support, Long.MAX_VALUE is returned. Perhaps this should return
113: * -1, but you should return MAX_VALUE on the assumption that if
114: * you can't determine the time, it's maximally new.
115: */
116: public long lastModified() {
117: if (myFile != null) {
118: return myFile.lastModified();
119: } else if (myUrl != null) {
120: try {
121: return myUrl.openConnection().getLastModified(); // Hail Mary
122: } catch (IOException e) {
123: return Long.MAX_VALUE;
124: }
125: }
126: return 0; // can't happen
127: }
128:
129: /**
130: * Returns the directory containing the resource, or null if the
131: * resource isn't directly available on the filesystem.
132: * This value can be used to locate the configuration file on disk,
133: * or to write files in the same directory.
134: */
135: public String getDirectory() {
136: if (myFile != null) {
137: return myFile.getParent();
138: } else if (myUrl != null) {
139: return null;
140: }
141: return null;
142: }
143:
144: // Returns true if found
145: private boolean tryClasspath(String filename) {
146: if (filename == null)
147: return false;
148: String classpath = System.getProperty("java.class.path");
149: String[] paths = split(classpath, File.pathSeparator);
150: myFile = searchDirectories(paths, filename);
151: return (myFile != null);
152: }
153:
154: private static File searchDirectories(String[] paths,
155: String filename) {
156: SecurityException exception = null;
157: for (int i = 0; i < paths.length; i++) {
158: try {
159: File file = new File(paths[i], filename);
160: if (file.exists() && !file.isDirectory()) {
161: return file;
162: }
163: } catch (SecurityException e) {
164: // Security exceptions can usually be ignored, but if all attempts
165: // to find the file fail, report the (last) security exception.
166: exception = e;
167: }
168: }
169: // Couldn't find any match
170: if (exception != null) {
171: throw exception;
172: } else {
173: return null;
174: }
175: }
176:
177: // Splits a String into pieces according to a delimiter.
178: // Uses JDK 1.1 classes for backward compatibility.
179: // JDK 1.4 actually has a split( ) method now.
180: private static String[] split(String str, String delim) {
181: // Use a Vector to hold the split strings.
182: Vector v = new Vector();
183:
184: // Use a StringTokenizer to do the splitting.
185: StringTokenizer tokenizer = new StringTokenizer(str, delim);
186: while (tokenizer.hasMoreTokens()) {
187: v.addElement(tokenizer.nextToken());
188: }
189:
190: String[] ret = new String[v.size()];
191: v.copyInto(ret);
192: return ret;
193: }
194:
195: // Returns true if found
196: private boolean tryLoader(String name) {
197: name = "/" + name;
198: URL res = ResourceLocator.class.getResource(name);
199: if (res == null) {
200: return false;
201: }
202:
203: // Try converting from a URL to a File.
204: File resFile = urlToFile(res);
205: if (resFile != null) {
206: myFile = resFile;
207: } else {
208: myUrl = res;
209: }
210: return true;
211: }
212:
213: private static File urlToFile(URL res) {
214: String externalForm = res.toExternalForm();
215: if (externalForm.startsWith("file:")) {
216: return new File(externalForm.substring(5));
217: }
218: return null;
219: }
220:
221: public String toString() {
222: return "[Resource: File: " + myFile + " URL: " + myUrl + "]";
223: }
224:
225: }
|