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 }