View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.vfs2.provider.zip;
18  
19  import java.io.InputStream;
20  import java.util.HashSet;
21  import java.util.zip.ZipEntry;
22  
23  import org.apache.commons.vfs2.FileName;
24  import org.apache.commons.vfs2.FileSystemException;
25  import org.apache.commons.vfs2.FileType;
26  import org.apache.commons.vfs2.provider.AbstractFileName;
27  import org.apache.commons.vfs2.provider.AbstractFileObject;
28  
29  /**
30   * A file in a ZIP file system.
31   */
32  public class ZipFileObject extends AbstractFileObject<ZipFileSystem> {
33  
34      /** The ZipEntry. */
35      protected ZipEntry entry;
36      private final HashSet<String> children = new HashSet<>();
37      private FileType type;
38  
39      protected ZipFileObject(final AbstractFileName name, final ZipEntry entry, final ZipFileSystem fs,
40              final boolean zipExists) throws FileSystemException {
41          super(name, fs);
42          setZipEntry(entry);
43          if (!zipExists) {
44              type = FileType.IMAGINARY;
45          }
46      }
47  
48      /**
49       * Sets the details for this file object.
50       *
51       * @param entry ZIP information related to this file.
52       */
53      protected void setZipEntry(final ZipEntry entry) {
54          if (this.entry != null) {
55              return;
56          }
57  
58          if (entry == null || entry.isDirectory()) {
59              type = FileType.FOLDER;
60          } else {
61              type = FileType.FILE;
62          }
63  
64          this.entry = entry;
65      }
66  
67      /**
68       * Attaches a child.
69       * <p>
70       * TODO: Shouldn't this method have package-only visibility? Cannot change this without breaking binary
71       * compatibility.
72       * </p>
73       *
74       * @param childName The name of the child.
75       */
76      public void attachChild(final FileName childName) {
77          children.add(childName.getBaseName());
78      }
79  
80      /**
81       * Determines if this file can be written to.
82       *
83       * @return {@code true} if this file is writable, {@code false} if not.
84       * @throws FileSystemException if an error occurs.
85       */
86      @Override
87      public boolean isWriteable() throws FileSystemException {
88          return false;
89      }
90  
91      /**
92       * Returns the file's type.
93       */
94      @Override
95      protected FileType doGetType() {
96          return type;
97      }
98  
99      /**
100      * Lists the children of the file.
101      */
102     @Override
103     protected String[] doListChildren() {
104         try {
105             if (!getType().hasChildren()) {
106                 return null;
107             }
108         } catch (final FileSystemException e) {
109             // should not happen as the type has already been cached.
110             throw new RuntimeException(e);
111         }
112 
113         return children.toArray(new String[children.size()]);
114     }
115 
116     /**
117      * Returns the size of the file content (in bytes). Is only called if {@link #doGetType} returns
118      * {@link FileType#FILE}.
119      */
120     @Override
121     protected long doGetContentSize() {
122         return entry.getSize();
123     }
124 
125     /**
126      * Returns the last modified time of this file.
127      */
128     @Override
129     protected long doGetLastModifiedTime() throws Exception {
130         return entry.getTime();
131     }
132 
133     /**
134      * Creates an input stream to read the file content from. Is only called if {@link #doGetType} returns
135      * {@link FileType#FILE}. The input stream returned by this method is guaranteed to be closed before this method is
136      * called again.
137      */
138     @Override
139     protected InputStream doGetInputStream() throws Exception {
140         // VFS-210: zip allows to gather an input stream even from a directory and will
141         // return -1 on the first read. getType should not be expensive and keeps the tests
142         // running
143         if (!getType().hasContent()) {
144             throw new FileSystemException("vfs.provider/read-not-file.error", getName());
145         }
146 
147         return getAbstractFileSystem().getZipFile().getInputStream(entry);
148     }
149 
150     @Override
151     protected void doAttach() throws Exception {
152         getAbstractFileSystem().getZipFile();
153     }
154 
155     @Override
156     protected void doDetach() throws Exception {
157         final ZipFileSystem afs = getAbstractFileSystem();
158         if (!afs.isOpen()) {
159             afs.close();
160         }
161     }
162 }