001: // ========================================================================
002: // Copyright 1996-2005 Mort Bay Consulting Pty. Ltd.
003: // ------------------------------------------------------------------------
004: // Licensed under the Apache License, Version 2.0 (the "License");
005: // you may not use this file except in compliance with the License.
006: // You may obtain a copy of the License at
007: // http://www.apache.org/licenses/LICENSE-2.0
008: // Unless required by applicable law or agreed to in writing, software
009: // distributed under the License is distributed on an "AS IS" BASIS,
010: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011: // See the License for the specific language governing permissions and
012: // limitations under the License.
013: // ========================================================================
014: package org.mortbay.resource;
015:
016: import java.io.File;
017: import java.io.FileInputStream;
018: import java.io.FileOutputStream;
019: import java.io.IOException;
020: import java.io.InputStream;
021: import java.io.OutputStream;
022: import java.net.MalformedURLException;
023: import java.net.URI;
024: import java.net.URISyntaxException;
025: import java.net.URL;
026: import java.net.URLConnection;
027: import java.security.Permission;
028:
029: import org.mortbay.log.Log;
030: import org.mortbay.util.URIUtil;
031:
032: /* ------------------------------------------------------------ */
033: /** File Resource.
034: *
035: * Handle resources of implied or explicit file type.
036: * This class can check for aliasing in the filesystem (eg case
037: * insensitivity). By default this is turned on, or it can be controlled with the
038: * "org.mortbay.util.FileResource.checkAliases" system parameter.
039: *
040: * @author Greg Wilkins (gregw)
041: */
042: public class FileResource extends URLResource {
043: private static boolean __checkAliases;
044: static {
045: __checkAliases = "true".equalsIgnoreCase(System.getProperty(
046: "org.mortbay.util.FileResource.checkAliases", "true"));
047:
048: if (__checkAliases)
049: Log.debug("Checking Resource aliases");
050: }
051:
052: /* ------------------------------------------------------------ */
053: private File _file;
054: private transient URL _alias = null;
055: private transient boolean _aliasChecked = false;
056:
057: /* ------------------------------------------------------------------------------- */
058: /** setCheckAliases.
059: * @param checkAliases True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
060: */
061: public static void setCheckAliases(boolean checkAliases) {
062: __checkAliases = checkAliases;
063: }
064:
065: /* ------------------------------------------------------------------------------- */
066: /** getCheckAliases.
067: * @return True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
068: */
069: public static boolean getCheckAliases() {
070: return __checkAliases;
071: }
072:
073: /* -------------------------------------------------------- */
074: public FileResource(URL url) throws IOException, URISyntaxException {
075: super (url, null);
076:
077: try {
078: // Try standard API to convert URL to file.
079: _file = new File(new URI(url.toString()));
080: } catch (Exception e) {
081: Log.ignore(e);
082: try {
083: // Assume that File.toURL produced unencoded chars. So try
084: // encoding them.
085: String file_url = "file:"
086: + URIUtil.encodePath(url.toString()
087: .substring(5));
088: URI uri = new URI(file_url);
089: if (uri.getAuthority() == null)
090: _file = new File(uri);
091: else
092: _file = new File("//" + uri.getAuthority()
093: + URIUtil.decodePath(url.getFile()));
094: } catch (Exception e2) {
095: Log.ignore(e2);
096:
097: // Still can't get the file. Doh! try good old hack!
098: checkConnection();
099: Permission perm = _connection.getPermission();
100: _file = new File(perm == null ? url.getFile() : perm
101: .getName());
102: }
103: }
104: if (_file.isDirectory()) {
105: if (!_urlString.endsWith("/"))
106: _urlString = _urlString + "/";
107: } else {
108: if (_urlString.endsWith("/"))
109: _urlString = _urlString.substring(0, _urlString
110: .length() - 1);
111: }
112:
113: }
114:
115: /* -------------------------------------------------------- */
116: FileResource(URL url, URLConnection connection, File file) {
117: super (url, connection);
118: _file = file;
119: if (_file.isDirectory() && !_urlString.endsWith("/"))
120: _urlString = _urlString + "/";
121: }
122:
123: /* -------------------------------------------------------- */
124: public Resource addPath(String path) throws IOException,
125: MalformedURLException {
126: URLResource r = null;
127:
128: if (!isDirectory()) {
129: r = (FileResource) super .addPath(path);
130: } else {
131: path = org.mortbay.util.URIUtil.canonicalPath(path);
132: if (path == null)
133: throw new MalformedURLException();
134:
135: // treat all paths being added as relative
136: String rel = path;
137: if (path.startsWith("/"))
138: rel = path.substring(1);
139:
140: r = (URLResource) Resource.newResource(URIUtil.addPaths(
141: _urlString, URIUtil.encodePath(rel)));
142: }
143:
144: String encoded = URIUtil.encodePath(path);
145: int expected = r.toString().length() - encoded.length();
146: int index = r._urlString.lastIndexOf(encoded, expected);
147:
148: if (expected != index
149: && ((expected - 1) != index || path.endsWith("/") || !r
150: .isDirectory())) {
151: if (!(r instanceof BadResource)) {
152: ((FileResource) r)._alias = r._url;
153: ((FileResource) r)._aliasChecked = true;
154: }
155: }
156: return r;
157: }
158:
159: /* ------------------------------------------------------------ */
160: public URL getAlias() {
161: if (__checkAliases && !_aliasChecked) {
162: try {
163: String abs = _file.getAbsolutePath();
164: String can = _file.getCanonicalPath();
165:
166: if (abs.length() != can.length() || !abs.equals(can))
167: _alias = new File(can).toURI().toURL();
168:
169: _aliasChecked = true;
170:
171: if (_alias != null && Log.isDebugEnabled()) {
172: Log.debug("ALIAS abs=" + abs);
173: Log.debug("ALIAS can=" + can);
174: }
175: } catch (Exception e) {
176: Log.warn(Log.EXCEPTION, e);
177: return getURL();
178: }
179: }
180: return _alias;
181: }
182:
183: /* -------------------------------------------------------- */
184: /**
185: * Returns true if the resource exists.
186: */
187: public boolean exists() {
188: return _file.exists();
189: }
190:
191: /* -------------------------------------------------------- */
192: /**
193: * Returns the last modified time
194: */
195: public long lastModified() {
196: return _file.lastModified();
197: }
198:
199: /* -------------------------------------------------------- */
200: /**
201: * Returns true if the respresenetd resource is a container/directory.
202: */
203: public boolean isDirectory() {
204: return _file.isDirectory();
205: }
206:
207: /* --------------------------------------------------------- */
208: /**
209: * Return the length of the resource
210: */
211: public long length() {
212: return _file.length();
213: }
214:
215: /* --------------------------------------------------------- */
216: /**
217: * Returns the name of the resource
218: */
219: public String getName() {
220: return _file.getAbsolutePath();
221: }
222:
223: /* ------------------------------------------------------------ */
224: /**
225: * Returns an File representing the given resource or NULL if this
226: * is not possible.
227: */
228: public File getFile() {
229: return _file;
230: }
231:
232: /* --------------------------------------------------------- */
233: /**
234: * Returns an input stream to the resource
235: */
236: public InputStream getInputStream() throws IOException {
237: return new FileInputStream(_file);
238: }
239:
240: /* --------------------------------------------------------- */
241: /**
242: * Returns an output stream to the resource
243: */
244: public OutputStream getOutputStream() throws java.io.IOException,
245: SecurityException {
246: return new FileOutputStream(_file);
247: }
248:
249: /* --------------------------------------------------------- */
250: /**
251: * Deletes the given resource
252: */
253: public boolean delete() throws SecurityException {
254: return _file.delete();
255: }
256:
257: /* --------------------------------------------------------- */
258: /**
259: * Rename the given resource
260: */
261: public boolean renameTo(Resource dest) throws SecurityException {
262: if (dest instanceof FileResource)
263: return _file.renameTo(((FileResource) dest)._file);
264: else
265: return false;
266: }
267:
268: /* --------------------------------------------------------- */
269: /**
270: * Returns a list of resources contained in the given resource
271: */
272: public String[] list() {
273: String[] list = _file.list();
274: if (list == null)
275: return null;
276: for (int i = list.length; i-- > 0;) {
277: if (new File(_file, list[i]).isDirectory()
278: && !list[i].endsWith("/"))
279: list[i] += "/";
280: }
281: return list;
282: }
283:
284: /* ------------------------------------------------------------ */
285: /** Encode according to this resource type.
286: * File URIs are encoded.
287: * @param uri URI to encode.
288: * @return The uri unchanged.
289: */
290: public String encode(String uri) {
291: return uri;
292: }
293:
294: /* ------------------------------------------------------------ */
295: /**
296: * @param o
297: * @return <code>true</code> of the object <code>o</code> is a {@link FileResource} pointing to the same file as this resource.
298: */
299: public boolean equals(Object o) {
300: if (this == o)
301: return true;
302:
303: if (null == o || !(o instanceof FileResource))
304: return false;
305:
306: FileResource f = (FileResource) o;
307: return f._file == _file
308: || (null != _file && _file.equals(f._file));
309: }
310:
311: /* ------------------------------------------------------------ */
312: /**
313: * @return the hashcode.
314: */
315: public int hashCode() {
316: return null == _file ? super.hashCode() : _file.hashCode();
317: }
318: }
|