View Javadoc

1   /**
2    *
3    * Copyright 2004 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  package org.apache.geronimo.deployment.util;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.Enumeration;
25  import java.util.Iterator;
26  import java.util.LinkedList;
27  import java.util.jar.JarEntry;
28  import java.util.jar.JarFile;
29  import java.util.jar.Manifest;
30  import java.util.zip.ZipEntry;
31  
32  /**
33   * @version $Rev: 394960 $ $Date: 2006-04-18 08:02:36 -0700 (Tue, 18 Apr 2006) $
34   */
35  public class NestedJarFile extends JarFile {
36      private JarFile baseJar;
37      private String basePath;
38      private boolean isClosed = false;
39      private boolean manifestLoaded = false;
40      private Manifest manifest;
41      private File tempFile;
42  
43      public NestedJarFile(JarFile jarFile, String path) throws IOException {
44          super(DeploymentUtil.DUMMY_JAR_FILE);
45  
46          // verify that the jar actually contains that path
47          JarEntry targetEntry = jarFile.getJarEntry(path + "/");
48          if (targetEntry == null) {
49              targetEntry = jarFile.getJarEntry(path);
50              if (targetEntry == null) {
51                  throw new IOException("Jar entry does not exist: jarFile=" + jarFile.getName() + ", path=" + path);
52              }
53          }
54  
55          if (targetEntry.isDirectory()) {
56              baseJar = jarFile;
57              if (!path.endsWith("/")) {
58                  path += "/";
59              }
60              basePath = path;
61          } else {
62              if (targetEntry instanceof UnpackedJarEntry) {
63                  // for unpacked jars we don't need to copy the jar file
64                  // out to a temp directory, since it is already available
65                  // as a raw file
66                  File targetFile = ((UnpackedJarEntry) targetEntry).getFile();
67                  baseJar = new JarFile(targetFile);
68                  basePath = "";
69              } else {
70                  tempFile = DeploymentUtil.toFile(jarFile, targetEntry.getName());
71                  baseJar = new JarFile(tempFile);
72                  basePath = "";
73              }
74          }
75      }
76  
77      public boolean isUnpacked() {
78          if (isClosed) {
79              throw new IllegalStateException("NestedJarFile is closed");
80          }
81          return basePath.length() > 0;
82      }
83  
84      public boolean isPacked() {
85          if (isClosed) {
86              throw new IllegalStateException("NestedJarFile is closed");
87          }
88          return basePath.length() == 0;
89      }
90  
91      public JarFile getBaseJar() {
92          if (isClosed) {
93              throw new IllegalStateException("NestedJarFile is closed");
94          }
95          return baseJar;
96      }
97  
98      public String getBasePath() {
99          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 }