View Javadoc
1   /*
2    * Copyright 2007 The Codehaus Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.codehaus.plexus.archiver.zip;
17  
18  import java.io.Closeable;
19  import java.io.File;
20  import java.io.IOException;
21  import java.net.URL;
22  import java.net.URLClassLoader;
23  import java.nio.charset.Charset;
24  import java.util.Enumeration;
25  import java.util.Iterator;
26  import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
27  import org.apache.commons.compress.archivers.zip.ZipFile;
28  import org.codehaus.plexus.components.io.functions.SymlinkDestinationSupplier;
29  import org.codehaus.plexus.components.io.resources.AbstractPlexusIoArchiveResourceCollection;
30  import org.codehaus.plexus.components.io.resources.EncodingSupported;
31  import org.codehaus.plexus.components.io.resources.PlexusIoResource;
32  import org.codehaus.plexus.components.io.resources.PlexusIoURLResource;
33  
34  public class PlexusIoZipFileResourceCollection
35      extends AbstractPlexusIoArchiveResourceCollection
36      implements EncodingSupported
37  {
38  
39      /**
40       * The zip file resource collections role hint.
41       */
42      public static final String ROLE_HINT = "zipFile";
43  
44      /**
45       * The zip file resource collections role hint for jar files.
46       */
47      public static final String JAR_ROLE_HINT = "jarFile";
48  
49      private Charset charset = Charset.forName( "UTF-8" );
50  
51      public PlexusIoZipFileResourceCollection()
52      {
53  
54      }
55  
56      @Override
57      public boolean isConcurrentAccessSupported()
58      {
59          // Maybe we could support concurrent some time in the future
60          return false;
61      }
62  
63      @Override
64      protected Iterator<PlexusIoResource> getEntries()
65          throws IOException
66      {
67          final File f = getFile();
68          if ( f == null )
69          {
70              throw new IOException( "The zip file has not been set." );
71          }
72          final URLClassLoader urlClassLoader = new URLClassLoader( new URL[]
73          {
74              f.toURI().toURL()
75          }, null )
76          {
77  
78              @Override
79              public URL getResource( String name )
80              {
81                  return findResource( name );
82              }
83  
84          };
85  
86          final URL url = new URL( "jar:" + f.toURI().toURL() + "!/" );
87          final ZipFile zipFile = new ZipFile( f, charset != null ? charset.name() : "UTF8" );
88          final Enumeration<ZipArchiveEntry> en = zipFile.getEntriesInPhysicalOrder();
89          return new ZipFileResourceIterator( en, url, zipFile, urlClassLoader );
90      }
91  
92      private static class ZipFileResourceIterator
93          implements Iterator<PlexusIoResource>, Closeable
94      {
95  
96          private class ZipFileResource
97              extends PlexusIoURLResource
98          {
99  
100             private ZipFileResource( ZipArchiveEntry entry )
101             {
102                 super( entry.getName(),
103                        entry.getTime() == -1 ? PlexusIoResource.UNKNOWN_MODIFICATION_DATE : entry.getTime(),
104                        entry.isDirectory() ? PlexusIoResource.UNKNOWN_RESOURCE_SIZE : entry.getSize(),
105                        !entry.isDirectory(), entry.isDirectory(), true );
106 
107             }
108 
109             @Override
110             public URL getURL()
111                 throws IOException
112             {
113                 String spec = getName();
114                 if ( spec.startsWith( "/" ) )
115                 {
116                     // Code path for PLXCOMP-170. Note that urlClassloader does not seem to produce correct
117                     // urls for this. Which again means files loaded via this path cannot have file names
118                     // requiring url encoding
119                     spec = "./" + spec;
120                     return new URL( url, spec );
121                 }
122                 return urlClassLoader.getResource( spec );
123             }
124 
125         }
126 
127         private class ZipFileSymlinkResource
128             extends ZipFileResource
129             implements SymlinkDestinationSupplier
130         {
131 
132             private final ZipArchiveEntry entry;
133 
134             private ZipFileSymlinkResource( ZipArchiveEntry entry )
135             {
136                 super( entry );
137 
138                 this.entry = entry;
139             }
140 
141             @Override
142             public String getSymlinkDestination()
143                 throws IOException
144             {
145                 return zipFile.getUnixSymlink( entry );
146             }
147 
148             @Override
149             public boolean isSymbolicLink()
150             {
151                 return true;
152             }
153 
154         }
155 
156         private final Enumeration<ZipArchiveEntry> en;
157 
158         private final URL url;
159 
160         private final ZipFile zipFile;
161 
162         private final URLClassLoader urlClassLoader;
163 
164         public ZipFileResourceIterator( Enumeration<ZipArchiveEntry> en, URL url, ZipFile zipFile,
165                                         URLClassLoader urlClassLoader )
166         {
167             this.en = en;
168             this.url = url;
169             this.zipFile = zipFile;
170             this.urlClassLoader = urlClassLoader;
171         }
172 
173         @Override
174         public boolean hasNext()
175         {
176             return en.hasMoreElements();
177         }
178 
179         @Override
180         public PlexusIoResource next()
181         {
182             final ZipArchiveEntry entry = en.nextElement();
183             return entry.isUnixSymlink()
184                        ? new ZipFileSymlinkResource( entry )
185                        : new ZipFileResource( entry );
186 
187         }
188 
189         @Override
190         public void remove()
191         {
192             throw new UnsupportedOperationException( "Removing isn't implemented." );
193         }
194 
195         @Override
196         public void close()
197             throws IOException
198         {
199             zipFile.close();
200         }
201 
202     }
203 
204     @Override
205     public void setEncoding( Charset charset )
206     {
207         this.charset = charset;
208     }
209 
210 }