View Javadoc
1   package org.apache.maven.shared.utils;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.util.Date;
28  import java.util.zip.ZipEntry;
29  import java.util.zip.ZipInputStream;
30  import org.apache.maven.shared.utils.io.FileUtils;
31  
32  /**
33   * Expand will unpack the given zip archive.
34   *
35   * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
36   */
37  class Expand
38  {
39      /**
40       * Source file which should get expanded
41       */
42      private File source;
43  
44      /**
45       * destination directory
46       */
47      private File dest;
48  
49      /**
50       * if the unpackaging should get performed if the destination already exists.
51       */
52      private boolean overwrite = false;
53  
54      private static final int BUFFER_SIZE = 2 ^ 16;
55  
56  
57      /**
58       * The zip archive which should get expanded.
59       *
60       * @param sourceArchive
61       */
62      public void setSrc( File sourceArchive )
63      {
64          this.source = sourceArchive;
65      }
66  
67      /**
68       * Set the destination directory into which the archive should get expanded.
69       * The directory will get created if it doesn't yet exist
70       * while executing the expand.
71       *
72       * @param destinationDirectory
73       */
74      public void setDest( File destinationDirectory )
75      {
76          this.dest = destinationDirectory;
77      }
78  
79      /**
80       * If the destination directory should get overwritten if the content
81       * already exists. If <code>false</code> we will only overwrite if the local
82       * file or directory is older than the one in the archive.
83       *
84       * @param overwrite
85       */
86      public void setOverwrite( boolean overwrite )
87      {
88          this.overwrite = overwrite;
89      }
90  
91      /**
92       * Actually perform the unpacking of the source archive
93       * into the destination directory.
94       *
95       * @throws Exception
96       */
97      public void execute()
98          throws Exception
99      {
100         expandFile( source, dest );
101     }
102 
103     /**
104      * <p>It is intended to be overwritten when implementing an own unarchiver</p>
105      * <p/>
106      * <p><b>Note:</b> we kept this protected method for the sake of backward compatibility!</p>
107      *
108      * @param srcFile
109      * @param dest
110      * @throws Exception
111      */
112     void expandFile( File srcFile, File dest )
113         throws Exception
114     {
115         if ( source == null )
116         {
117             throw new NullPointerException( "Source Archive must not be null!" );
118         }
119 
120         File destDir = dest;
121         if ( destDir == null )
122         {
123             destDir = new File( System.getProperty( "user.dir" ) );
124         }
125 
126         FileInputStream fileInputStream = new FileInputStream( srcFile );
127         try
128         {
129             ZipInputStream zipInputStream = new ZipInputStream( fileInputStream );
130 
131             ZipEntry zipEntry;
132 
133             while ( ( zipEntry = zipInputStream.getNextEntry() ) != null )
134             {
135                 String zipEntryName = zipEntry.getName();
136                 Date zipEntryDate = new Date( zipEntry.getTime() );
137 
138                 extractFile( source, destDir, zipInputStream, zipEntryName, zipEntryDate, zipEntry.isDirectory() );
139             }
140         }
141         finally
142         {
143             try
144             {
145                 fileInputStream.close();
146             }
147             catch ( IOException ioe )
148             {
149                 // no worries, all is ok ...
150             }
151         }
152     }
153 
154     /**
155      * Extract a single ZipEntry.
156      * <p/>
157      * <p><b>Note:</b> we kept this protected method for the sake of backward compatibility!</p>
158      *
159      * @param archive               the archive to unpack
160      * @param destDir               the destination dirctory
161      * @param compressedInputStream
162      * @param entryName
163      * @param entryDate
164      * @param isDirectory
165      * @throws Exception
166      */
167     void extractFile( File archive, File destDir, InputStream compressedInputStream, String entryName,
168                                 Date entryDate, boolean isDirectory )
169         throws Exception
170     {
171         File targetFile = new File( destDir, entryName );
172 
173         // if overwrite is specified and the file type
174         // of the existing file does not match, then delete it
175         if ( overwrite && targetFile.exists() && targetFile.isDirectory() != isDirectory )
176         {
177             deleteFileOrDir( targetFile );
178         }
179 
180         if ( !targetFile.exists() || overwrite || targetFile.lastModified() <= entryDate.getTime() )
181         {
182             if ( isDirectory )
183             {
184                 targetFile.mkdirs();
185             }
186             else
187             {
188                 byte[] buffer = new byte[BUFFER_SIZE];
189                 FileOutputStream fileOutputStream = new FileOutputStream( targetFile );
190                 try
191                 {
192                     int len;
193                     while ( ( len = compressedInputStream.read( buffer ) ) > 0 )
194                     {
195                         fileOutputStream.write( buffer, 0, len );
196                     }
197                 }
198                 finally
199                 {
200                     try
201                     {
202                         fileOutputStream.close();
203                     }
204                     catch ( IOException ioe )
205                     {
206                         // no worries, all is ok ...
207                     }
208                 }
209                 targetFile.setLastModified( entryDate.getTime() );
210             }
211         }
212     }
213 
214     /**
215      * small helper method who deletes the given directory or file.
216      *
217      * @param targetFile
218      * @throws IOException
219      */
220     private void deleteFileOrDir( File targetFile )
221         throws IOException
222     {
223         if ( targetFile.isDirectory() )
224         {
225             FileUtils.deleteDirectory( targetFile );
226         }
227         else
228         {
229             FileUtils.delete( targetFile );
230         }
231 
232     }
233 }