001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  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: 566266 $ $Date: 2007-08-15 13:05:16 -0400 (Wed, 15 Aug 2007) $
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        // be careful to clean up the temp file... we tell the vm to delete this on exit
075        // but VMs can't be trusted to acutally delete the file
076        private static File createTempFile(String extension) throws IOException {
077            File tempFile = File.createTempFile("geronimo-deploymentUtil", extension == null? ".tmpdir": extension);
078            tempFile.deleteOnExit();
079            return tempFile;
080        }
081    
082    
083        public static void copyFile(File source, File destination) throws IOException {
084            File destinationDir = destination.getParentFile();
085            if (false == destinationDir.exists() && false == destinationDir.mkdirs()) {
086                throw new java.io.IOException("Cannot create directory : " + destinationDir);
087            }
088            
089            InputStream in = null;
090            OutputStream out = null;
091            try {
092                in = new FileInputStream(source);
093                out = new FileOutputStream(destination);
094                writeAll(in, out);
095            } finally {
096                close(in);
097                close(out);
098            }
099        }
100    
101        private static void writeAll(InputStream in, OutputStream out) throws IOException {
102            byte[] buffer = new byte[4096];
103            int count;
104            while ((count = in.read(buffer)) > 0) {
105                out.write(buffer, 0, count);
106            }
107            out.flush();
108        }
109        public static File toTempFile(JarFile jarFile, String path) throws IOException {
110            return toTempFile(createJarURL(jarFile, path));
111        }
112    
113        public static File toTempFile(URL url) throws IOException {
114            InputStream in = null;
115            OutputStream out = null;
116            try {
117                in = url.openStream();
118    
119                int index = url.getPath().lastIndexOf(".");
120                String extension = null;
121                if (index > 0) {
122                    extension = url.getPath().substring(index);
123                }
124                File tempFile = createTempFile(extension);
125    
126                out = new FileOutputStream(tempFile);
127    
128                writeAll(in, out);
129                return tempFile;
130            } finally {
131                close(out);
132                close(in);
133            }
134        }
135    
136        public static String readAll(URL url) throws IOException {
137            Reader reader = null;
138            try {
139                reader = new InputStreamReader(url.openStream());
140    
141                char[] buffer = new char[4000];
142                StringBuffer out = new StringBuffer();
143                for(int count = reader.read(buffer); count >= 0; count = reader.read(buffer)) {
144                    out.append(buffer, 0, count);
145                }
146                return out.toString();
147            } finally {
148                close(reader);
149            }
150        }
151    
152        public static File toFile(JarFile jarFile) throws IOException {
153            if (jarFile instanceof UnpackedJarFile) {
154                return ((UnpackedJarFile) jarFile).getBaseDir();
155            } else {
156                    throw new IOException("jarFile is not a directory");
157            }
158        }
159    
160        // be careful with this method as it can leave a temp lying around
161        public static File toFile(JarFile jarFile, String path) throws IOException {
162            if (jarFile instanceof UnpackedJarFile) {
163                File baseDir = ((UnpackedJarFile) jarFile).getBaseDir();
164                File file = new File(baseDir, path);
165                if (!file.isFile()) {
166                    throw new IOException("No such file: " + file.getAbsolutePath());
167                }
168                return file;
169            } else {
170                String urlString = "jar:" + new File(jarFile.getName()).toURL() + "!/" + path;
171                return toTempFile(new URL(urlString));
172            }
173        }
174    
175        public static URL createJarURL(JarFile jarFile, String path) throws MalformedURLException {
176            if (jarFile instanceof NestedJarFile) {
177                NestedJarFile nestedJar = (NestedJarFile) jarFile;
178                if (nestedJar.isUnpacked()) {
179                    JarFile baseJar = nestedJar.getBaseJar();
180                    String basePath = nestedJar.getBasePath();
181                    if (baseJar instanceof UnpackedJarFile) {
182                        File baseDir = ((UnpackedJarFile) baseJar).getBaseDir();
183                        baseDir = new File(baseDir, basePath);
184                        return new File(baseDir, path).toURL();
185                    }
186                }
187            }
188            
189            if (jarFile instanceof UnpackedJarFile) {
190                File baseDir = ((UnpackedJarFile) jarFile).getBaseDir();
191                return new File(baseDir, path).toURL();
192            } else {
193                String urlString = "jar:" + new File(jarFile.getName()).toURL() + "!/" + path;
194                return new URL(urlString);
195            }
196        }
197    
198        public static JarFile createJarFile(File jarFile) throws IOException {
199            if (jarFile.isDirectory()) {
200                return new UnpackedJarFile(jarFile);
201            } else {
202                return new JarFile(jarFile);
203            }
204        }
205    
206        public static void copyToPackedJar(JarFile inputJar, File outputFile) throws IOException {
207            if (inputJar.getClass() == JarFile.class) {
208                // this is a plain old jar... nothign special
209                copyFile(new File(inputJar.getName()), outputFile);
210            } else if (inputJar instanceof NestedJarFile && ((NestedJarFile)inputJar).isPacked()) {
211                NestedJarFile nestedJarFile = (NestedJarFile)inputJar;
212                JarFile baseJar = nestedJarFile.getBaseJar();
213                String basePath = nestedJarFile.getBasePath();
214                if (baseJar instanceof UnpackedJarFile) {
215                    // our target jar is just a file in upacked jar (a plain old directory)... now
216                    // we just need to find where it is and copy it to the outptu
217                    copyFile(((UnpackedJarFile)baseJar).getFile(basePath), outputFile);
218                } else {
219                    // out target is just a plain old jar file directly accessabel from the file system
220                    copyFile(new File(baseJar.getName()), outputFile);
221                }
222            } else {
223                // copy out the module contents to a standalone jar file (entry by entry)
224                JarOutputStream out = null;
225                try {
226                    out = new JarOutputStream(new FileOutputStream(outputFile));
227                    byte[] buffer = new byte[4096];
228                    Enumeration entries = inputJar.entries();
229                    while (entries.hasMoreElements()) {
230                        ZipEntry entry = (ZipEntry) entries.nextElement();
231                        InputStream in = inputJar.getInputStream(entry);
232                        try {
233                            out.putNextEntry(new ZipEntry(entry.getName()));
234                            try {
235                                int count;
236                                while ((count = in.read(buffer)) > 0) {
237                                    out.write(buffer, 0, count);
238                                }
239                            } finally {
240                                out.closeEntry();
241                            }
242                        } finally {
243                            close(in);
244                        }
245                    }
246                } finally {
247                    close(out);
248                }
249            }
250        }
251    
252        public static void jarDirectory(File sourceDirecotry, File destinationFile) throws IOException {
253            JarFile inputJar = new UnpackedJarFile(sourceDirecotry);
254            try {
255                copyToPackedJar(inputJar, destinationFile);
256            } finally {
257                close(inputJar);
258            }
259        }
260    
261        private static void createDirectory(File dir) throws IOException {
262            if (dir != null && !dir.exists()) {
263                boolean success = dir.mkdirs();
264                if (!success) {
265                    throw new IOException("Cannot create directory " + dir.getAbsolutePath());
266                }
267            }
268        }
269    
270        public static void unzipToDirectory(ZipFile zipFile, File destDir) throws IOException {
271            Enumeration entries = zipFile.entries();
272            try {
273                while (entries.hasMoreElements()) {
274                    ZipEntry entry = (ZipEntry) entries.nextElement();
275                    if (entry.isDirectory()) {
276                        File dir = new File(destDir, entry.getName());
277                        createDirectory(dir);
278                    } else {
279                        File file = new File(destDir, entry.getName());
280                        createDirectory(file.getParentFile());
281                        OutputStream out = null;
282                        InputStream in = null;
283                        try {
284                            out = new BufferedOutputStream(new FileOutputStream(file));
285                            in = zipFile.getInputStream(entry);
286                            writeAll(in, out);
287                        } finally {
288                            if (null != out) {
289                                out.close();
290                            }
291                            if (null != in) {
292                                in.close();
293                            }
294                        }
295                    }
296                }
297            } finally {
298                zipFile.close();
299            }
300        }
301        
302        
303        public static boolean recursiveDelete(File root, Collection unableToDeleteCollection) {
304            if (root == null) {
305                return true;
306            }
307    
308            if (root.isDirectory()) {
309                File[] files = root.listFiles();
310                if (files != null) {
311                    for (int i = 0; i < files.length; i++) {
312                        File file = files[i];
313                        if (file.isDirectory()) {
314                            recursiveDelete(file, unableToDeleteCollection);
315                        } else {
316                            if (!file.delete() && unableToDeleteCollection != null) {
317                                unableToDeleteCollection.add(file.getAbsolutePath());    
318                            }
319                        }
320                        // help out the GC of file handles by nulling the references
321                        file = null;
322                        files[i] = null;
323                    }
324                }
325            }
326            boolean rootDeleteStatus = false;
327            if (!(rootDeleteStatus = root.delete()) && unableToDeleteCollection != null) 
328                    unableToDeleteCollection.add(root);
329            
330            return rootDeleteStatus;
331        }
332        
333        public static boolean recursiveDelete(File root) {
334            return recursiveDelete(root,null);
335        }
336    
337        public static Collection listRecursiveFiles(File file) {
338            LinkedList list = new LinkedList();
339            listRecursiveFiles(file, list);
340            return Collections.unmodifiableCollection(list);
341        }
342    
343        public static void listRecursiveFiles(File file, Collection collection) {
344            File[] files = file.listFiles();
345            if ( null == files ) {
346                return;
347            }
348            for (int i = 0; i < files.length; i++) {
349                collection.add(files[i]);
350                if (files[i].isDirectory()) {
351                    listRecursiveFiles(files[i], collection);
352                }
353            }
354        }
355    
356        public static void flush(OutputStream thing) {
357            if (thing != null) {
358                try {
359                    thing.flush();
360                } catch(Exception ignored) {
361                }
362            }
363        }
364    
365        public static void flush(Writer thing) {
366            if (thing != null) {
367                try {
368                    thing.flush();
369                } catch(Exception ignored) {
370                }
371            }
372        }
373    
374        public static void close(JarFile thing) {
375            if (thing != null) {
376                try {
377                    thing.close();
378                } catch(Exception ignored) {
379                }
380            }
381        }
382    
383        public static void close(InputStream thing) {
384            if (thing != null) {
385                try {
386                    thing.close();
387                } catch(Exception ignored) {
388                }
389            }
390        }
391    
392        public static void close(OutputStream thing) {
393            if (thing != null) {
394                try {
395                    thing.close();
396                } catch(Exception ignored) {
397                }
398            }
399        }
400    
401        public static void close(Reader thing) {
402            if (thing != null) {
403                try {
404                    thing.close();
405                } catch(Exception ignored) {
406                }
407            }
408        }
409    
410        public static void close(Writer thing) {
411            if (thing != null) {
412                try {
413                    thing.close();
414                } catch(Exception ignored) {
415                }
416            }
417        }
418    
419        public static final class EmptyInputStream extends InputStream {
420            public int read() {
421                return -1;
422            }
423    
424            public int read(byte b[])  {
425                return -1;
426            }
427    
428            public int read(byte b[], int off, int len) {
429                return -1;
430            }
431    
432            public long skip(long n) {
433                return 0;
434            }
435    
436            public int available() {
437                return 0;
438            }
439    
440            public void close() {
441            }
442    
443            public synchronized void mark(int readlimit) {
444            }
445    
446            public synchronized void reset() {
447            }
448    
449            public boolean markSupported() {
450                return false;
451            }
452        }
453    }