001 /**
002 *
003 * Copyright 2004 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.geronimo.deployment.util;
018
019 import java.io.File;
020 import java.io.IOException;
021 import java.io.InputStream;
022 import java.util.Collection;
023 import java.util.Collections;
024 import java.util.Enumeration;
025 import java.util.Iterator;
026 import java.util.LinkedList;
027 import java.util.jar.JarEntry;
028 import java.util.jar.JarFile;
029 import java.util.jar.Manifest;
030 import java.util.zip.ZipEntry;
031
032 /**
033 * @version $Rev: 394960 $ $Date: 2006-04-18 08:02:36 -0700 (Tue, 18 Apr 2006) $
034 */
035 public class NestedJarFile extends JarFile {
036 private JarFile baseJar;
037 private String basePath;
038 private boolean isClosed = false;
039 private boolean manifestLoaded = false;
040 private Manifest manifest;
041 private File tempFile;
042
043 public NestedJarFile(JarFile jarFile, String path) throws IOException {
044 super(DeploymentUtil.DUMMY_JAR_FILE);
045
046 // verify that the jar actually contains that path
047 JarEntry targetEntry = jarFile.getJarEntry(path + "/");
048 if (targetEntry == null) {
049 targetEntry = jarFile.getJarEntry(path);
050 if (targetEntry == null) {
051 throw new IOException("Jar entry does not exist: jarFile=" + jarFile.getName() + ", path=" + path);
052 }
053 }
054
055 if (targetEntry.isDirectory()) {
056 baseJar = jarFile;
057 if (!path.endsWith("/")) {
058 path += "/";
059 }
060 basePath = path;
061 } else {
062 if (targetEntry instanceof UnpackedJarEntry) {
063 // for unpacked jars we don't need to copy the jar file
064 // out to a temp directory, since it is already available
065 // as a raw file
066 File targetFile = ((UnpackedJarEntry) targetEntry).getFile();
067 baseJar = new JarFile(targetFile);
068 basePath = "";
069 } else {
070 tempFile = DeploymentUtil.toFile(jarFile, targetEntry.getName());
071 baseJar = new JarFile(tempFile);
072 basePath = "";
073 }
074 }
075 }
076
077 public boolean isUnpacked() {
078 if (isClosed) {
079 throw new IllegalStateException("NestedJarFile is closed");
080 }
081 return basePath.length() > 0;
082 }
083
084 public boolean isPacked() {
085 if (isClosed) {
086 throw new IllegalStateException("NestedJarFile is closed");
087 }
088 return basePath.length() == 0;
089 }
090
091 public JarFile getBaseJar() {
092 if (isClosed) {
093 throw new IllegalStateException("NestedJarFile is closed");
094 }
095 return baseJar;
096 }
097
098 public String getBasePath() {
099 if (isClosed) {
100 throw new IllegalStateException("NestedJarFile is closed");
101 }
102 return basePath;
103 }
104
105 public Manifest getManifest() throws IOException {
106 if (isClosed) {
107 throw new IllegalStateException("NestedJarFile is closed");
108 }
109
110 if (!manifestLoaded) {
111 JarEntry manifestEntry = getBaseEntry("META-INF/MANIFEST.MF");
112
113 if (manifestEntry != null && !manifestEntry.isDirectory()) {
114 InputStream in = null;
115 try {
116 in = baseJar.getInputStream(manifestEntry);
117 manifest = new Manifest(in);
118 } finally {
119 if (in != null) {
120 try {
121 in.close();
122 } catch (IOException e) {
123 // ignore
124 }
125 }
126 }
127 }
128 manifestLoaded = true;
129 }
130 return manifest;
131 }
132
133 public NestedJarEntry getNestedJarEntry(String name) {
134 if (isClosed) {
135 throw new IllegalStateException("NestedJarFile is closed");
136 }
137
138 JarEntry baseEntry = getBaseEntry(name);
139 if (baseEntry == null) {
140 return null;
141 }
142 return new NestedJarEntry(name, baseEntry, getManifestSafe());
143 }
144
145 public JarEntry getJarEntry(String name) {
146 if (isClosed) {
147 throw new IllegalStateException("NestedJarFile is closed");
148 }
149
150 return getNestedJarEntry(name);
151 }
152
153 public ZipEntry getEntry(String name) {
154 if (isClosed) {
155 throw new IllegalStateException("NestedJarFile is closed");
156 }
157
158 return getNestedJarEntry(name);
159 }
160
161 public Enumeration entries() {
162 if (isClosed) {
163 throw new IllegalStateException("NestedJarFile is closed");
164 }
165
166 Collection baseEntries = Collections.list(baseJar.entries());
167 Collection entries = new LinkedList();
168 for (Iterator iterator = baseEntries.iterator(); iterator.hasNext();) {
169 JarEntry baseEntry = (JarEntry) iterator.next();
170 String path = baseEntry.getName();
171 if (path.startsWith(basePath)) {
172 entries.add(new NestedJarEntry(path.substring(basePath.length()), baseEntry, getManifestSafe()));
173 }
174 }
175 return Collections.enumeration(entries);
176 }
177
178 public InputStream getInputStream(ZipEntry zipEntry) throws IOException {
179 if (isClosed) {
180 throw new IllegalStateException("NestedJarFile is closed");
181 }
182
183 JarEntry baseEntry;
184 if (zipEntry instanceof NestedJarEntry) {
185 baseEntry = ((NestedJarEntry)zipEntry).getBaseEntry();
186 } else {
187 baseEntry = getBaseEntry(zipEntry.getName());
188 }
189
190 if (baseEntry == null) {
191 throw new IOException("Entry not found: name=" + baseEntry.getName());
192 } else if (baseEntry.isDirectory()) {
193 return new DeploymentUtil.EmptyInputStream();
194 }
195 return baseJar.getInputStream(baseEntry);
196 }
197
198 public String getName() {
199 return baseJar.getName();
200 }
201
202 /**
203 * Always returns -1.
204 * @return -1
205 */
206 public int size() {
207 if (isClosed) {
208 throw new IllegalStateException("NestedJarFile is closed");
209 }
210 return -1;
211 }
212
213 public void close() throws IOException {
214 if (isClosed) {
215 return;
216 }
217
218 try {
219 if (baseJar != null && isPacked()) {
220 baseJar.close();
221 }
222 } finally {
223 isClosed = true;
224 baseJar = null;
225 basePath = null;
226 manifestLoaded = false;
227 manifest = null;
228 if (tempFile != null) {
229 tempFile.delete();
230 tempFile = null;
231 }
232 }
233 }
234
235 protected void finalize() throws IOException {
236 close();
237 }
238
239 private JarEntry getBaseEntry(String name) {
240 return baseJar.getJarEntry(basePath + name);
241 }
242
243 private Manifest getManifestSafe() {
244 Manifest manifest = null;
245 try {
246 manifest = getManifest();
247 } catch (IOException e) {
248 // ignore
249 }
250 return manifest;
251 }
252
253 }