View Javadoc

1   package com.atlassian.plugin.util.zip;
2   
3   import org.apache.commons.io.IOUtils;
4   import org.apache.commons.io.FileUtils;
5   import org.apache.commons.logging.Log;
6   import org.apache.commons.logging.LogFactory;
7   
8   import java.io.*;
9   import java.util.zip.ZipEntry;
10  import java.util.zip.ZipInputStream;
11  import java.util.*;
12  
13  public abstract class AbstractUnzipper implements Unzipper
14  {
15      protected static Log log = LogFactory.getLog(FileUnzipper.class);
16      protected File destDir;
17  
18      protected File saveEntry(InputStream is, ZipEntry entry) throws IOException
19      {
20          File file = new File(destDir, entry.getName());
21  
22          if (entry.isDirectory())
23          {
24              file.mkdirs();
25          }
26          else
27          {
28              File dir = new File(file.getParent());
29              dir.mkdirs();
30  
31              FileOutputStream fos = null;
32              try
33              {
34                  fos = new FileOutputStream(file);
35                  IOUtils.copy(is, fos);
36                  fos.flush();
37              }
38              catch (FileNotFoundException fnfe)
39              {
40                  log.error("Error extracting a file to '" + destDir + File.separator + entry.getName() + "'. This destination is invalid for writing an extracted file stream to. ");
41                  return null;
42              }
43              finally
44              {
45                  IOUtils.closeQuietly(fos);
46              }
47          }
48          file.setLastModified(entry.getTime());
49  
50          return file;
51      }
52  
53      protected ZipEntry[] entries(ZipInputStream zis) throws IOException
54      {
55          List entries = new ArrayList();
56          try
57          {
58              ZipEntry zipEntry = zis.getNextEntry();
59              while (zipEntry != null)
60              {
61                  entries.add(zipEntry);
62                  zis.closeEntry();
63                  zipEntry = zis.getNextEntry();
64              }
65          }
66          finally
67          {
68              IOUtils.closeQuietly(zis);
69          }
70  
71          return (ZipEntry[]) entries.toArray(new ZipEntry[entries.size()]);
72      }
73  
74      public void conditionalUnzip() throws IOException
75      {
76          Map<String,Long> zipContentsAndLastModified = new HashMap<String,Long>();
77  
78          ZipEntry[] zipEntries = entries();
79          for (int i = 0; i < zipEntries.length; i++)
80          {
81              zipContentsAndLastModified.put(zipEntries[i].getName(), zipEntries[i].getTime());
82          }
83  
84          // If the jar contents of the directory does not match the contents of the zip
85          // The we will nuke the bundled plugins directory and re-extract.
86          Map<String,Long> targetDirContents = getContentsOfTargetDir(destDir);
87          if (!targetDirContents.equals(zipContentsAndLastModified))
88          {
89              FileUtils.deleteDirectory(destDir);
90              unzip();
91          }
92          else
93          {
94              if (log.isDebugEnabled())
95                  log.debug("Target directory contents match zip contents. Do nothing.");
96          }
97      }
98  
99      private Map<String,Long> getContentsOfTargetDir(File dir)
100     {
101         // Create filter that lists only jars
102         FilenameFilter filter = new FilenameFilter()
103         {
104             public boolean accept(File dir, String name)
105             {
106                 return name.endsWith(".jar");
107             }
108         };
109 
110 
111         if (!dir.isDirectory())
112         {
113             return Collections.emptyMap();
114         }
115 
116         Map<String,Long> targetDirContents = new HashMap<String,Long>();
117         for (File child : dir.listFiles())
118         {
119             if (log.isDebugEnabled())
120             {
121                 log.debug("Examining entry in zip: "+child);
122             }
123             targetDirContents.put(child.getName(), child.lastModified());
124         }
125 
126         return targetDirContents;
127     }
128 }