1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.mortbay.resource;
15
16 import java.io.File;
17 import java.io.FileOutputStream;
18 import java.io.FilterInputStream;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.net.JarURLConnection;
22 import java.net.URL;
23 import java.util.jar.JarEntry;
24 import java.util.jar.JarInputStream;
25 import java.util.jar.Manifest;
26
27 import org.mortbay.log.Log;
28 import org.mortbay.util.IO;
29 import org.mortbay.util.URIUtil;
30
31
32
33 public class JarResource extends URLResource
34 {
35
36 protected transient JarURLConnection _jarConnection;
37
38
39 JarResource(URL url)
40 {
41 super(url,null);
42 }
43
44
45 JarResource(URL url, boolean useCaches)
46 {
47 super(url, null, useCaches);
48 }
49
50
51 public synchronized void release()
52 {
53 _jarConnection=null;
54 super.release();
55 }
56
57
58 protected boolean checkConnection()
59 {
60 super.checkConnection();
61 try
62 {
63 if (_jarConnection!=_connection)
64 newConnection();
65 }
66 catch(IOException e)
67 {
68 Log.ignore(e);
69 _jarConnection=null;
70 }
71
72 return _jarConnection!=null;
73 }
74
75
76
77
78
79 protected void newConnection() throws IOException
80 {
81 _jarConnection=(JarURLConnection)_connection;
82 }
83
84
85
86
87
88 public boolean exists()
89 {
90 if (_urlString.endsWith("!/"))
91 return checkConnection();
92 else
93 return super.exists();
94 }
95
96
97 public File getFile()
98 throws IOException
99 {
100 return null;
101 }
102
103
104 public InputStream getInputStream()
105 throws java.io.IOException
106 {
107 checkConnection();
108 if (!_urlString.endsWith("!/"))
109 return new FilterInputStream(super.getInputStream())
110 {
111 public void close() throws IOException {this.in=IO.getClosedStream();}
112 };
113
114 URL url = new URL(_urlString.substring(4,_urlString.length()-2));
115 InputStream is = url.openStream();
116 return is;
117 }
118
119
120 public static void extract(Resource resource, File directory, boolean deleteOnExit)
121 throws IOException
122 {
123 if(Log.isDebugEnabled())Log.debug("Extract "+resource+" to "+directory);
124
125
126 String urlString = resource.getURL().toExternalForm().trim();
127 int endOfJarUrl = urlString.indexOf("!/");
128 int startOfJarUrl = (endOfJarUrl >= 0?4:0);
129
130 if (endOfJarUrl < 0)
131 throw new IOException("Not a valid jar url: "+urlString);
132
133 URL jarFileURL = new URL(urlString.substring(startOfJarUrl, endOfJarUrl));
134 String subEntryName = (endOfJarUrl+2 < urlString.length() ? urlString.substring(endOfJarUrl + 2) : null);
135 boolean subEntryIsDir = (subEntryName != null && subEntryName.endsWith("/")?true:false);
136
137 if (Log.isDebugEnabled()) Log.debug("Extracting entry = "+subEntryName+" from jar "+jarFileURL);
138
139 InputStream is = jarFileURL.openConnection().getInputStream();
140 JarInputStream jin = new JarInputStream(is);
141 JarEntry entry;
142 boolean shouldExtract;
143 String directoryCanonicalPath = directory.getCanonicalPath()+"/";
144 while((entry=jin.getNextJarEntry())!=null)
145 {
146 String entryName = entry.getName();
147 if ((subEntryName != null) && (entryName.startsWith(subEntryName)))
148 {
149
150
151 if (subEntryIsDir)
152 {
153
154
155
156
157 entryName = entryName.substring(subEntryName.length());
158 if (!entryName.equals(""))
159 {
160
161 shouldExtract = true;
162 }
163 else
164 shouldExtract = false;
165 }
166 else
167 shouldExtract = true;
168 }
169 else if ((subEntryName != null) && (!entryName.startsWith(subEntryName)))
170 {
171
172
173 shouldExtract = false;
174 }
175 else
176 {
177
178 shouldExtract = true;
179 }
180
181
182 if (!shouldExtract)
183 {
184 if (Log.isDebugEnabled()) Log.debug("Skipping entry: "+entryName);
185 continue;
186 }
187
188 String dotCheck = entryName.replace('\\', '/');
189 dotCheck = URIUtil.canonicalPath(dotCheck);
190 if (dotCheck == null)
191 {
192 if (Log.isDebugEnabled()) Log.debug("Invalid entry: "+entryName);
193 continue;
194 }
195
196 File file=new File(directory,entryName);
197
198 if (entry.isDirectory())
199 {
200
201 if (!file.exists())
202 file.mkdirs();
203 }
204 else
205 {
206
207 File dir = new File(file.getParent());
208 if (!dir.exists())
209 dir.mkdirs();
210
211
212 FileOutputStream fout = null;
213 try
214 {
215 fout = new FileOutputStream(file);
216 IO.copy(jin,fout);
217 }
218 finally
219 {
220 IO.close(fout);
221 }
222
223
224 if (entry.getTime()>=0)
225 file.setLastModified(entry.getTime());
226 }
227 if (deleteOnExit)
228 file.deleteOnExit();
229 }
230
231 if ((subEntryName == null) || (subEntryName != null && subEntryName.equalsIgnoreCase("META-INF/MANIFEST.MF")))
232 {
233 Manifest manifest = jin.getManifest();
234 if (manifest != null)
235 {
236 File metaInf = new File (directory, "META-INF");
237 metaInf.mkdir();
238 File f = new File(metaInf, "MANIFEST.MF");
239 FileOutputStream fout = new FileOutputStream(f);
240 manifest.write(fout);
241 fout.close();
242 }
243 }
244 IO.close(jin);
245 }
246
247
248 public void extract(File directory, boolean deleteOnExit)
249 throws IOException
250 {
251 extract(this,directory,deleteOnExit);
252 }
253 }