View Javadoc

1   package org.appfuse;
2   
3   import org.codehaus.plexus.util.StringUtils;
4   import org.codehaus.plexus.util.SelectorUtils;
5   
6   import java.io.File;
7   import java.io.FileOutputStream;
8   import java.io.IOException;
9   import java.io.InputStream;
10  import java.util.Enumeration;
11  import java.util.jar.JarOutputStream;
12  import java.util.regex.Matcher;
13  import java.util.regex.Pattern;
14  import java.util.zip.ZipEntry;
15  import java.util.zip.ZipFile;
16  
17  /**
18   * Static utility class to help with War file processing.
19   */
20  public class WarPathUtils
21  {
22    public static final Pattern WEBINF_CLASSES_PATTERN;
23  
24    static
25    {
26      WEBINF_CLASSES_PATTERN = Pattern.compile("^[/\\\\]?web-inf[/\\\\]classes[/\\\\]?(.*)$", Pattern.CASE_INSENSITIVE);
27    }
28  
29    /**
30     * Unpack the WEB-INF/classes directory from the specified war file if the contents of the target
31     * directory is older than the war file.
32     *
33     * @param warFile        The war file to unpack.
34     * @param classesJarFile The target jar file which will hold the contents of the WEB-INF/classes directory.
35     * @param includes Comma separated list of resource patterns to include in the path
36     * @param excludes Comma separated list of resource patterns to exclude from the path.
37     * @throws IOException if an I/O error occurs.
38     */
39    public static void unpackWarClassesIfNewer(File warFile, File classesJarFile, String includes, String excludes) throws IOException
40    {
41      boolean process = false;
42      if (!classesJarFile.exists() || warFile.lastModified() > classesJarFile.lastModified())
43      {
44        process = true;
45      }
46  
47      if (process)
48      {
49        ZipFile zipFile = new ZipFile(warFile);
50        JarOutputStream classesJarOutputStream = new JarOutputStream(new FileOutputStream(classesJarFile));
51        try
52        {
53          unpackWebInfClasses(zipFile, classesJarOutputStream, includes, excludes);
54        }
55        finally
56        {
57          closeZipFile(zipFile);
58          closeOutputStream(classesJarOutputStream);
59        }
60      }
61    }
62  
63    private static void closeOutputStream(JarOutputStream classesJarOutputStream)
64    {
65      if (classesJarOutputStream != null)
66      {
67        try
68        {
69          classesJarOutputStream.close();
70        }
71        catch (IOException e)
72        {
73          // do nothing.
74        }
75      }
76    }
77  
78    private static void closeZipFile(ZipFile zipFile)
79    {
80      if (zipFile != null)
81      {
82        try
83        {
84          zipFile.close();
85        }
86        catch (IOException e)
87        {
88          // do nothing.
89        }
90      }
91    }
92  
93    /**
94     * Extract the WEB-INF/classes entries from the specified war file into the named directory.
95     *
96     * @param zipFile                The war file to unpack
97     * @param classesJarOutputStream The target directory.
98     * @param includes               Comma separated patterns to match against resources to include
99     * @param excludes               Comma separated patterns to match against resources to exclude
100    * @throws IOException if an I/O error occurs during the unpacking.
101    */
102   public static void unpackWebInfClasses(ZipFile zipFile, JarOutputStream classesJarOutputStream, String includes, String excludes) throws IOException
103   {
104     Enumeration zipEntries = zipFile.entries();
105 
106     String[] includePatterns;
107 
108     if (StringUtils.isNotEmpty(includes))
109     {
110       includePatterns = StringUtils.split(includes, ",");
111     }
112     else
113     {
114       includePatterns = new String[]{"**"};
115     }
116 
117     String[] excludesPattern;
118 
119     if (StringUtils.isNotEmpty(excludes))
120     {
121       excludesPattern = StringUtils.split(excludes, ",");
122     }
123     else
124     {
125       excludesPattern = new String[0];
126     }
127 
128     while (zipEntries.hasMoreElements())
129     {
130       ZipEntry zipEntry = (ZipEntry) zipEntries.nextElement();
131       Matcher matcher = WEBINF_CLASSES_PATTERN.matcher(zipEntry.getName());
132       if (matcher.matches() && matcher.group(1).length() > 0)
133       {
134         String classesEntry = matcher.group(1);
135 
136         if (matches(classesEntry, includePatterns))
137         {
138           if (!matches(classesEntry, excludesPattern))
139           {
140             ZipEntry jarEntry = new ZipEntry(classesEntry);
141 
142             jarEntry.setComment(zipEntry.getComment());
143             jarEntry.setExtra(zipEntry.getExtra());
144             jarEntry.setMethod(zipEntry.getMethod());
145             jarEntry.setTime(zipEntry.getTime());
146             jarEntry.setSize(zipEntry.getSize());
147             jarEntry.setCompressedSize(zipEntry.getCompressedSize());
148             jarEntry.setCrc(zipEntry.getCrc());
149             classesJarOutputStream.putNextEntry(jarEntry);
150             byte[] readBuffer = new byte[1024];
151             int readLength;
152             InputStream inputStream = zipFile.getInputStream(zipEntry);
153             while ((readLength = inputStream.read(readBuffer)) >= 0)
154             {
155               classesJarOutputStream.write(readBuffer, 0, readLength);
156             }
157           }
158         }
159       }
160     }
161   }
162 
163   private static boolean matches(String entry, String[] patterns)
164   {
165     entry = replaceFileSeparator(entry);
166     for (int i = 0; i < patterns.length; i++)
167     {
168       String pattern = replaceFileSeparator(patterns[i].trim());
169       if (SelectorUtils.matchPath(pattern, entry))
170       {
171         return true;
172       }
173 
174     }
175     return false;
176   }
177 
178   private static String replaceFileSeparator(String path)
179   {
180     path = path.replace('/', File.separatorChar);
181     path = path.replace('\\', File.separatorChar);
182     return path;
183   }
184 
185 }