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.FileOutputStream;
018: import java.io.IOException;
019: import java.io.InputStream;
020: import java.net.JarURLConnection;
021: import java.net.URL;
022: import java.util.jar.JarEntry;
023: import java.util.jar.JarInputStream;
024:
025: import org.mortbay.log.Log;
026: import org.mortbay.util.IO;
027:
028: /* ------------------------------------------------------------ */
029: public class JarResource extends URLResource {
030:
031: protected transient JarURLConnection _jarConnection;
032:
033: /* -------------------------------------------------------- */
034: JarResource(URL url) {
035: super (url, null);
036: }
037:
038: /* ------------------------------------------------------------ */
039: JarResource(URL url, boolean useCaches) {
040: super (url, null, useCaches);
041: }
042:
043: /* ------------------------------------------------------------ */
044: public synchronized void release() {
045: _jarConnection = null;
046: super .release();
047: }
048:
049: /* ------------------------------------------------------------ */
050: protected boolean checkConnection() {
051: super .checkConnection();
052: try {
053: if (_jarConnection != _connection)
054: newConnection();
055: } catch (IOException e) {
056: Log.ignore(e);
057: _jarConnection = null;
058: }
059:
060: return _jarConnection != null;
061: }
062:
063: /* ------------------------------------------------------------ */
064: /**
065: * @throws IOException Sub-classes of <code>JarResource</code> may throw an IOException (or subclass)
066: */
067: protected void newConnection() throws IOException {
068: _jarConnection = (JarURLConnection) _connection;
069: }
070:
071: /* ------------------------------------------------------------ */
072: /**
073: * Returns true if the respresenetd resource exists.
074: */
075: public boolean exists() {
076: if (_urlString.endsWith("!/"))
077: return checkConnection();
078: else
079: return super .exists();
080: }
081:
082: /* ------------------------------------------------------------ */
083: public File getFile() throws IOException {
084: return null;
085: }
086:
087: /* ------------------------------------------------------------ */
088: public InputStream getInputStream() throws java.io.IOException {
089: checkConnection();
090: if (!_urlString.endsWith("!/"))
091: return super .getInputStream();
092:
093: URL url = new URL(_urlString.substring(4,
094: _urlString.length() - 2));
095: InputStream is = url.openStream();
096: return is;
097: }
098:
099: /* ------------------------------------------------------------ */
100: public static void extract(Resource resource, File directory,
101: boolean deleteOnExit) throws IOException {
102: if (Log.isDebugEnabled())
103: Log.debug("Extract " + resource + " to " + directory);
104:
105: String urlString = resource.getURL().toExternalForm().trim();
106: int endOfJarUrl = urlString.indexOf("!/");
107: int startOfJarUrl = (endOfJarUrl >= 0 ? 4 : 0);
108:
109: if (endOfJarUrl < 0)
110: throw new IOException("Not a valid jar url: " + urlString);
111:
112: URL jarFileURL = new URL(urlString.substring(startOfJarUrl,
113: endOfJarUrl));
114: String subEntryName = (endOfJarUrl + 2 < urlString.length() ? urlString
115: .substring(endOfJarUrl + 2)
116: : null);
117: boolean subEntryIsDir = (subEntryName != null
118: && subEntryName.endsWith("/") ? true : false);
119:
120: if (Log.isDebugEnabled())
121: Log.debug("Extracting entry = " + subEntryName
122: + " from jar " + jarFileURL);
123:
124: InputStream is = jarFileURL.openConnection().getInputStream();
125: JarInputStream jin = new JarInputStream(is);
126: JarEntry entry = null;
127: boolean shouldExtract = true;
128: while ((entry = jin.getNextJarEntry()) != null) {
129: String entryName = entry.getName();
130:
131: if ((subEntryName != null)
132: && (entryName.startsWith(subEntryName))) {
133: //if there is a particular subEntry that we are looking for, only
134: //extract it.
135: if (subEntryIsDir) {
136: //if it is a subdirectory we are looking for, then we
137: //are looking to extract its contents into the target
138: //directory. Remove the name of the subdirectory so
139: //that we don't wind up creating it too.
140: entryName = entryName.substring(subEntryName
141: .length());
142: if (!entryName.equals("")) {
143: //the entry is
144: shouldExtract = true;
145: } else
146: shouldExtract = false;
147: } else
148: shouldExtract = true;
149: } else if ((subEntryName != null)
150: && (!entryName.startsWith(subEntryName))) {
151: //there is a particular entry we are looking for, and this one
152: //isn't it
153: shouldExtract = false;
154: } else {
155: //we are extracting everything
156: shouldExtract = true;
157: }
158:
159: if (!shouldExtract) {
160: if (Log.isDebugEnabled())
161: Log.debug("Skipping entry: " + entryName);
162: continue;
163: }
164:
165: File file = new File(directory, entryName);
166: if (entry.isDirectory()) {
167: // Make directory
168: if (!file.exists())
169: file.mkdirs();
170: } else {
171: // make directory (some jars don't list dirs)
172: File dir = new File(file.getParent());
173: if (!dir.exists())
174: dir.mkdirs();
175:
176: // Make file
177: FileOutputStream fout = null;
178: try {
179: fout = new FileOutputStream(file);
180: IO.copy(jin, fout);
181: } finally {
182: IO.close(fout);
183: }
184:
185: // touch the file.
186: if (entry.getTime() >= 0)
187: file.setLastModified(entry.getTime());
188: }
189: if (deleteOnExit)
190: file.deleteOnExit();
191: }
192: }
193:
194: /* ------------------------------------------------------------ */
195: public void extract(File directory, boolean deleteOnExit)
196: throws IOException {
197: extract(this, directory, deleteOnExit);
198: }
199: }
|