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.IOException;
018: import java.net.JarURLConnection;
019: import java.net.URL;
020: import java.util.ArrayList;
021: import java.util.Enumeration;
022: import java.util.jar.JarEntry;
023: import java.util.jar.JarFile;
024:
025: import org.mortbay.log.Log;
026:
027: /* ------------------------------------------------------------ */
028: class JarFileResource extends JarResource {
029:
030: transient JarFile _jarFile;
031: transient File _file;
032: transient String[] _list;
033: transient JarEntry _entry;
034: transient boolean _directory;
035: transient String _jarUrl;
036: transient String _path;
037: transient boolean _exists;
038:
039: /* -------------------------------------------------------- */
040: JarFileResource(URL url) {
041: super (url);
042: }
043:
044: JarFileResource(URL url, boolean useCaches) {
045: super (url, useCaches);
046: }
047:
048: /* ------------------------------------------------------------ */
049: public synchronized void release() {
050: _list = null;
051: _entry = null;
052: _file = null;
053: _jarFile = null;
054: super .release();
055: }
056:
057: /* ------------------------------------------------------------ */
058: protected boolean checkConnection() {
059: try {
060: super .checkConnection();
061: } finally {
062: if (_jarConnection == null) {
063: _entry = null;
064: _file = null;
065: _jarFile = null;
066: _list = null;
067: }
068: }
069: return _jarFile != null;
070: }
071:
072: /* ------------------------------------------------------------ */
073: protected void newConnection() throws IOException {
074: super .newConnection();
075:
076: _entry = null;
077: _file = null;
078: _jarFile = null;
079: _list = null;
080:
081: int sep = _urlString.indexOf("!/");
082: _jarUrl = _urlString.substring(0, sep + 2);
083: _path = _urlString.substring(sep + 2);
084: if (_path.length() == 0)
085: _path = null;
086: _jarFile = _jarConnection.getJarFile();
087: _file = new File(_jarFile.getName());
088: }
089:
090: /* ------------------------------------------------------------ */
091: /**
092: * Returns true if the respresenetd resource exists.
093: */
094: public boolean exists() {
095: if (_exists)
096: return true;
097:
098: if (_urlString.endsWith("!/")) {
099:
100: String file_url = _urlString.substring(4, _urlString
101: .length() - 2);
102: try {
103: return newResource(file_url).exists();
104: } catch (Exception e) {
105: Log.ignore(e);
106: return false;
107: }
108: }
109:
110: boolean check = checkConnection();
111:
112: // Is this a root URL?
113: if (_jarUrl != null && _path == null) {
114: // Then if it exists it is a directory
115: _directory = check;
116: return true;
117: } else {
118: // Can we find a file for it?
119: JarFile jarFile = null;
120: if (check)
121: // Yes
122: jarFile = _jarFile;
123: else {
124: // No - so lets look if the root entry exists.
125: try {
126: JarURLConnection c = (JarURLConnection) ((new URL(
127: _jarUrl)).openConnection());
128: c.setUseCaches(getUseCaches());
129: jarFile = c.getJarFile();
130: } catch (Exception e) {
131: Log.ignore(e);
132: }
133: }
134:
135: // Do we need to look more closely?
136: if (jarFile != null && _entry == null && !_directory) {
137: // OK - we have a JarFile, lets look at the entries for our path
138: Enumeration e = jarFile.entries();
139: while (e.hasMoreElements()) {
140: JarEntry entry = (JarEntry) e.nextElement();
141: String name = entry.getName().replace('\\', '/');
142:
143: // Do we have a match
144: if (name.equals(_path)) {
145: _entry = entry;
146: // Is the match a directory
147: _directory = _path.endsWith("/");
148: break;
149: } else if (_path.endsWith("/")) {
150: if (name.startsWith(_path)) {
151: _directory = true;
152: break;
153: }
154: } else if (name.startsWith(_path)
155: && name.length() > _path.length()
156: && name.charAt(_path.length()) == '/') {
157: _directory = true;
158: break;
159: }
160: }
161: }
162: }
163:
164: _exists = (_directory || _entry != null);
165: return _exists;
166: }
167:
168: /* ------------------------------------------------------------ */
169: /**
170: * Returns true if the represented resource is a container/directory.
171: * If the resource is not a file, resources ending with "/" are
172: * considered directories.
173: */
174: public boolean isDirectory() {
175: return _urlString.endsWith("/") || exists() && _directory;
176: }
177:
178: /* ------------------------------------------------------------ */
179: /**
180: * Returns the last modified time
181: */
182: public long lastModified() {
183: if (checkConnection() && _file != null)
184: return _file.lastModified();
185: return -1;
186: }
187:
188: /* ------------------------------------------------------------ */
189: public synchronized String[] list() {
190:
191: if (isDirectory() && _list == null) {
192: ArrayList list = new ArrayList(32);
193:
194: checkConnection();
195:
196: JarFile jarFile = _jarFile;
197: if (jarFile == null) {
198: try {
199: JarURLConnection jc = (JarURLConnection) ((new URL(
200: _jarUrl)).openConnection());
201: jc.setUseCaches(getUseCaches());
202: jarFile = jc.getJarFile();
203: } catch (Exception e) {
204: Log.ignore(e);
205: }
206: }
207:
208: Enumeration e = jarFile.entries();
209: String dir = _urlString
210: .substring(_urlString.indexOf("!/") + 2);
211: while (e.hasMoreElements()) {
212:
213: JarEntry entry = (JarEntry) e.nextElement();
214: String name = entry.getName().replace('\\', '/');
215: if (!name.startsWith(dir)
216: || name.length() == dir.length()) {
217: continue;
218: }
219: String listName = name.substring(dir.length());
220: int dash = listName.indexOf('/');
221: if (dash >= 0) {
222: //when listing jar:file urls, you get back one
223: //entry for the dir itself, which we ignore
224: if (dash == 0 && listName.length() == 1)
225: continue;
226: //when listing jar:file urls, all files and
227: //subdirs have a leading /, which we remove
228: if (dash == 0)
229: listName = listName.substring(dash + 1,
230: listName.length());
231: else
232: listName = listName.substring(0, dash + 1);
233:
234: if (list.contains(listName))
235: continue;
236: }
237:
238: list.add(listName);
239: }
240:
241: _list = new String[list.size()];
242: list.toArray(_list);
243: }
244: return _list;
245: }
246:
247: /* ------------------------------------------------------------ */
248: /**
249: * Return the length of the resource
250: */
251: public long length() {
252: if (isDirectory())
253: return -1;
254:
255: if (_entry != null)
256: return _entry.getSize();
257:
258: return -1;
259: }
260:
261: /* ------------------------------------------------------------ */
262: /** Encode according to this resource type.
263: * File URIs are not encoded.
264: * @param uri URI to encode.
265: * @return The uri unchanged.
266: */
267: public String encode(String uri) {
268: return uri;
269: }
270:
271: /**
272: * Take a Resource that possibly might use URLConnection caching
273: * and turn it into one that doesn't.
274: * @param resource
275: * @return
276: */
277: public static Resource getNonCachingResource(Resource resource) {
278: if (!(resource instanceof JarFileResource))
279: return resource;
280:
281: JarFileResource oldResource = (JarFileResource) resource;
282:
283: JarFileResource newResource = new JarFileResource(oldResource
284: .getURL(), false);
285: return newResource;
286:
287: }
288: }
|