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.BufferedOutputStream;
020    import java.io.File;
021    import java.io.FileInputStream;
022    import java.io.FileOutputStream;
023    import java.io.IOException;
024    import java.io.InputStream;
025    import java.io.InputStreamReader;
026    import java.io.OutputStream;
027    import java.io.Reader;
028    import java.io.Writer;
029    import java.net.MalformedURLException;
030    import java.net.URL;
031    import java.util.Collection;
032    import java.util.Collections;
033    import java.util.Enumeration;
034    import java.util.LinkedList;
035    import java.util.jar.JarFile;
036    import java.util.jar.JarOutputStream;
037    import java.util.jar.Manifest;
038    import java.util.zip.ZipEntry;
039    import java.util.zip.ZipFile;
040    
041    /**
042     * @version $Rev: 399178 $ $Date: 2006-05-02 23:57:29 -0700 (Tue, 02 May 2006) $
043     */
044    public final class DeploymentUtil {
045        private DeploymentUtil() {
046        }
047    
048        public static final File DUMMY_JAR_FILE;
049        static {
050            try {
051                DUMMY_JAR_FILE = DeploymentUtil.createTempFile();
052                new JarOutputStream(new FileOutputStream(DeploymentUtil.DUMMY_JAR_FILE), new Manifest()).close();
053            } catch (IOException e) {
054                throw new ExceptionInInitializerError(e);
055            }
056        }
057    
058        // be careful to clean up the temp directory
059        public static File createTempDir() throws IOException {
060            File tempDir = File.createTempFile("geronimo-deploymentUtil", ".tmpdir");
061            tempDir.delete();
062            tempDir.mkdirs();
063            return tempDir;
064        }
065    
066        // be careful to clean up the temp file... we tell the vm to delete this on exit
067        // but VMs can't be trusted to acutally delete the file
068        public static File createTempFile() throws IOException {
069            File tempFile = File.createTempFile("geronimo-deploymentUtil", ".tmpdir");
070            tempFile.deleteOnExit();
071            return tempFile;
072        }
073    
074        public static void copyFile(File source, File destination) throws IOException {
075            File destinationDir = destination.getParentFile();
076            if (false == destinationDir.exists() && false == destinationDir.mkdirs()) {
077                throw new java.io.IOException("Cannot create directory : " + destinationDir);
078            }
079            
080            InputStream in = null;
081            OutputStream out = null;
082            try {
083                in = new FileInputStream(source);
084                out = new FileOutputStream(destination);
085                writeAll(in, out);
086            } finally {
087                close(in);
088                close(out);
089            }
090        }
091    
092        private static void writeAll(InputStream in, OutputStream out) throws IOException {
093            byte[] buffer = new byte[4096];
094            int count;
095            while ((count = in.read(buffer)) > 0) {
096                out.write(buffer, 0, count);
097            }
098            out.flush();
099        }
100        public static File toTempFile(JarFile jarFile, String path) throws IOException {
101            return toTempFile(createJarURL(jarFile, path));
102        }
103    
104        public static File toTempFile(URL url) throws IOException {
105            InputStream in = null;
106            OutputStream out = null;
107            try {
108                in = url.openStream();
109    
110                File tempFile = createTempFile();
111                out = new FileOutputStream(tempFile);
112    
113                writeAll(in, out);
114                return tempFile;
115            } finally {
116                close(out);
117                close(in);
118            }
119        }
120    
121        public static String readAll(URL url) throws IOException {
122            Reader reader = null;
123            try {
124                reader = new InputStreamReader(url.openStream());
125    
126                char[] buffer = new char[4000];
127                StringBuffer out = new StringBuffer();
128                for(int count = reader.read(buffer); count >= 0; count = reader.read(buffer)) {
129                    out.append(buffer, 0, count);
130                }
131                return out.toString();
132            } finally {
133                close(reader);
134            }
135        }
136    
137        public static File toFile(JarFile jarFile) throws IOException {
138            if (jarFile instanceof UnpackedJarFile) {
139                return ((UnpackedJarFile) jarFile).getBaseDir();
140            } else {
141                    throw new IOException("jarFile is not a directory");
142            }
143        }
144    
145        // be careful with this method as it can leave a temp lying around
146        public static File toFile(JarFile jarFile, String path) throws IOException {
147            if (jarFile instanceof UnpackedJarFile) {
148                File baseDir = ((UnpackedJarFile) jarFile).getBaseDir();
149                File file = new File(baseDir, path);
150                if (!file.isFile()) {
151                    throw new IOException("No such file: " + file.getAbsolutePath());
152                }
153                return file;
154            } else {
155                String urlString = "jar:" + new File(jarFile.getName()).toURL() + "!/" + path;
156                return toTempFile(new URL(urlString));
157            }
158        }
159    
160        public static URL createJarURL(JarFile jarFile, String path) throws MalformedURLException {
161            if (jarFile instanceof NestedJarFile) {
162                NestedJarFile nestedJar = (NestedJarFile) jarFile;
163                if (nestedJar.isUnpacked()) {
164                    JarFile baseJar = nestedJar.getBaseJar();
165                    String basePath = nestedJar.getBasePath();
166                    if (baseJar instanceof UnpackedJarFile) {
167                        File baseDir = ((UnpackedJarFile) baseJar).getBaseDir();
168                        baseDir = new File(baseDir, basePath);
169                        return new File(baseDir, path).toURL();
170                    }
171                }
172            }
173            
174            if (jarFile instanceof UnpackedJarFile) {
175                File baseDir = ((UnpackedJarFile) jarFile).getBaseDir();
176                return new File(baseDir, path).toURL();
177            } else {
178                String urlString = "jar:" + new File(jarFile.getName()).toURL() + "!/" + path;
179                return new URL(urlString);
180            }
181        }
182    
183        public static JarFile createJarFile(File jarFile) throws IOException {
184            if (jarFile.isDirectory()) {
185                return new UnpackedJarFile(jarFile);
186            } else {
187                return new JarFile(jarFile);
188            }
189        }
190    
191        public static void copyToPackedJar(JarFile inputJar, File outputFile) throws IOException {
192            if (inputJar.getClass() == JarFile.class) {
193                // this is a plain old jar... nothign special
194                copyFile(new File(inputJar.getName()), outputFile);
195            } else if (inputJar instanceof NestedJarFile && ((NestedJarFile)inputJar).isPacked()) {
196                NestedJarFile nestedJarFile = (NestedJarFile)inputJar;
197                JarFile baseJar = nestedJarFile.getBaseJar();
198                String basePath = nestedJarFile.getBasePath();
199                if (baseJar instanceof UnpackedJarFile) {
200                    // our target jar is just a file in upacked jar (a plain old directory)... now
201                    // we just need to find where it is and copy it to the outptu
202                    copyFile(((UnpackedJarFile)baseJar).getFile(basePath), outputFile);
203                } else {
204                    // out target is just a plain old jar file directly accessabel from the file system
205                    copyFile(new File(baseJar.getName()), outputFile);
206                }
207            } else {
208                // copy out the module contents to a standalone jar file (entry by entry)
209                JarOutputStream out = null;
210                try {
211                    out = new JarOutputStream(new FileOutputStream(outputFile));
212                    byte[] buffer = new byte[4096];
213                    Enumeration entries = inputJar.entries();
214                    while (entries.hasMoreElements()) {
215                        ZipEntry entry = (ZipEntry) entries.nextElement();
216                        InputStream in = inputJar.getInputStream(entry);
217                        try {
218                            out.putNextEntry(new ZipEntry(entry.getName()));
219                            try {
220                                int count;
221                                while ((count = in.read(buffer)) > 0) {
222                                    out.write(buffer, 0, count);
223                                }
224                            } finally {
225                                out.closeEntry();
226                            }
227                        } finally {
228                            close(in);
229                        }
230                    }
231                } finally {
232                    close(out);
233                }
234            }
235        }
236    
237        public static void jarDirectory(File sourceDirecotry, File destinationFile) throws IOException {
238            JarFile inputJar = new UnpackedJarFile(sourceDirecotry);
239            try {
240                copyToPackedJar(inputJar, destinationFile);
241            } finally {
242                close(inputJar);
243            }
244        }
245    
246        public static void unzipToDirectory(ZipFile zipFile, File destDir) throws IOException {
247            Enumeration entries = zipFile.entries();
248            try {
249                while (entries.hasMoreElements()) {
250                    ZipEntry entry = (ZipEntry) entries.nextElement();
251                    if (entry.isDirectory()) {
252                        File dir = new File(destDir, entry.getName());
253                        boolean success = dir.mkdirs();
254                        if (!success) {
255                            throw new IOException("Cannot create directory " + dir.getAbsolutePath());
256                        }
257                    } else {
258                        File file = new File(destDir, entry.getName());
259                        OutputStream out = null;
260                        InputStream in = null;
261                        try {
262                            out = new BufferedOutputStream(new FileOutputStream(file));
263                            in = zipFile.getInputStream(entry);
264                            writeAll(in, out);
265                        } finally {
266                            if (null != out) {
267                                out.close();
268                            }
269                            if (null != in) {
270                                in.close();
271                            }
272                        }
273                    }
274                }
275            } finally {
276                zipFile.close();
277            }
278        }
279        
280        
281        public static boolean recursiveDelete(File root, Collection unableToDeleteCollection) {
282            if (root == null) {
283                return true;
284            }
285    
286            if (root.isDirectory()) {
287                File[] files = root.listFiles();
288                if (files != null) {
289                    for (int i = 0; i < files.length; i++) {
290                        File file = files[i];
291                        if (file.isDirectory()) {
292                            recursiveDelete(file);
293                        } else {
294                            if (!file.delete() && unableToDeleteCollection != null) {
295                                unableToDeleteCollection.add(file);    
296                            }
297                        }
298                    }
299                }
300            }
301            return root.delete();
302        }
303        
304        public static boolean recursiveDelete(File root) {
305            return recursiveDelete(root,null);
306        }
307    
308        public static Collection listRecursiveFiles(File file) {
309            LinkedList list = new LinkedList();
310            listRecursiveFiles(file, list);
311            return Collections.unmodifiableCollection(list);
312        }
313    
314        public static void listRecursiveFiles(File file, Collection collection) {
315            File[] files = file.listFiles();
316            if ( null == files ) {
317                return;
318            }
319            for (int i = 0; i < files.length; i++) {
320                collection.add(files[i]);
321                if (files[i].isDirectory()) {
322                    listRecursiveFiles(files[i], collection);
323                }
324            }
325        }
326    
327        public static void flush(OutputStream thing) {
328            if (thing != null) {
329                try {
330                    thing.flush();
331                } catch(Exception ignored) {
332                }
333            }
334        }
335    
336        public static void flush(Writer thing) {
337            if (thing != null) {
338                try {
339                    thing.flush();
340                } catch(Exception ignored) {
341                }
342            }
343        }
344    
345        public static void close(JarFile thing) {
346            if (thing != null) {
347                try {
348                    thing.close();
349                } catch(Exception ignored) {
350                }
351            }
352        }
353    
354        public static void close(InputStream thing) {
355            if (thing != null) {
356                try {
357                    thing.close();
358                } catch(Exception ignored) {
359                }
360            }
361        }
362    
363        public static void close(OutputStream thing) {
364            if (thing != null) {
365                try {
366                    thing.close();
367                } catch(Exception ignored) {
368                }
369            }
370        }
371    
372        public static void close(Reader thing) {
373            if (thing != null) {
374                try {
375                    thing.close();
376                } catch(Exception ignored) {
377                }
378            }
379        }
380    
381        public static void close(Writer thing) {
382            if (thing != null) {
383                try {
384                    thing.close();
385                } catch(Exception ignored) {
386                }
387            }
388        }
389    
390        public static final class EmptyInputStream extends InputStream {
391            public int read() {
392                return -1;
393            }
394    
395            public int read(byte b[])  {
396                return -1;
397            }
398    
399            public int read(byte b[], int off, int len) {
400                return -1;
401            }
402    
403            public long skip(long n) {
404                return 0;
405            }
406    
407            public int available() {
408                return 0;
409            }
410    
411            public void close() {
412            }
413    
414            public synchronized void mark(int readlimit) {
415            }
416    
417            public synchronized void reset() {
418            }
419    
420            public boolean markSupported() {
421                return false;
422            }
423        }
424    }