View Javadoc
1   package org.codehaus.plexus.components.io.resources;
2   
3   /*
4    * Copyright 2007 The Codehaus Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import javax.annotation.Nonnull;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.net.URL;
27  import java.nio.file.Files;
28  import java.nio.file.attribute.FileTime;
29  
30  import org.apache.commons.io.IOUtils;
31  import org.apache.commons.io.output.DeferredFileOutputStream;
32  import org.codehaus.plexus.components.io.attributes.AttributeUtils;
33  import org.codehaus.plexus.components.io.attributes.FileAttributes;
34  import org.codehaus.plexus.components.io.attributes.PlexusIoResourceAttributes;
35  import org.codehaus.plexus.components.io.functions.ContentSupplier;
36  import org.codehaus.plexus.components.io.functions.FileSupplier;
37  import org.codehaus.plexus.components.io.functions.InputStreamTransformer;
38  import org.codehaus.plexus.components.io.functions.ResourceAttributeSupplier;
39  
40  import static java.util.Objects.requireNonNull;
41  
42  /**
43   * Implementation of {@link PlexusIoResource} for files.
44   */
45  public class PlexusIoFileResource extends AbstractPlexusIoResource implements ResourceAttributeSupplier, FileSupplier {
46  
47      @Nonnull
48      private final File file;
49  
50      @Nonnull
51      private final PlexusIoResourceAttributes attributes;
52  
53      @Nonnull
54      private final FileAttributes fileAttributes;
55  
56      private final ContentSupplier contentSupplier;
57  
58      private final DeferredFileOutputStream dfos;
59  
60      protected PlexusIoFileResource(@Nonnull File file, @Nonnull String name, @Nonnull PlexusIoResourceAttributes attrs)
61              throws IOException {
62          this(file, name, attrs, null, null);
63      }
64  
65      PlexusIoFileResource(
66              @Nonnull final File file,
67              @Nonnull String name,
68              @Nonnull PlexusIoResourceAttributes attrs,
69              final ContentSupplier contentSupplier,
70              final InputStreamTransformer streamTransformer)
71              throws IOException {
72          this(file, name, attrs, new FileAttributes(file, true), contentSupplier, streamTransformer);
73      }
74  
75      PlexusIoFileResource(
76              @Nonnull final File file,
77              @Nonnull String name,
78              @Nonnull PlexusIoResourceAttributes attrs,
79              @Nonnull FileAttributes fileAttributes,
80              final ContentSupplier contentSupplier,
81              final InputStreamTransformer streamTransformer)
82              throws IOException {
83          super(
84                  name,
85                  fileAttributes.getLastModifiedTime().toMillis(),
86                  fileAttributes.getSize(),
87                  fileAttributes.isRegularFile(),
88                  fileAttributes.isDirectory(),
89                  fileAttributes.isRegularFile()
90                          || fileAttributes.isDirectory()
91                          || fileAttributes.isSymbolicLink()
92                          || fileAttributes.isOther());
93          this.file = file;
94          this.attributes = requireNonNull(attrs, "attributes is null for file " + file.getName());
95          this.fileAttributes = requireNonNull(fileAttributes, "fileAttributes is null for file " + file.getName());
96          this.contentSupplier = contentSupplier != null ? contentSupplier : getRootContentSupplier(file);
97  
98          boolean hasTransformer = streamTransformer != null && streamTransformer != identityTransformer;
99          InputStreamTransformer transToUse = streamTransformer != null ? streamTransformer : identityTransformer;
100 
101         dfos = hasTransformer && file.isFile() ? asDeferredStream(this.contentSupplier, transToUse, this) : null;
102     }
103 
104     private static DeferredFileOutputStream asDeferredStream(
105             @Nonnull ContentSupplier supplier, @Nonnull InputStreamTransformer transToUse, PlexusIoResource resource)
106             throws IOException {
107         DeferredFileOutputStream dfos = DeferredFileOutputStream.builder()
108                 .setThreshold(5000000)
109                 .setPrefix("p-archiver")
110                 .get();
111         try (InputStream inputStream = supplier.getContents();
112                 InputStream transformed = transToUse.transform(resource, inputStream);
113                 DeferredFileOutputStream closeable = dfos) {
114             IOUtils.copy(transformed, dfos);
115         }
116         return dfos;
117     }
118 
119     private static ContentSupplier getRootContentSupplier(final File file) {
120         return () -> Files.newInputStream(file.toPath());
121     }
122 
123     public static String getName(File file) {
124         return file.getPath().replace('\\', '/');
125     }
126 
127     /**
128      * Returns the resource file.
129      */
130     @Nonnull
131     public File getFile() {
132         return file;
133     }
134 
135     @Nonnull
136     public InputStream getContents() throws IOException {
137         if (dfos == null) {
138             return contentSupplier.getContents();
139         }
140         if (dfos.isInMemory()) {
141             return new ByteArrayInputStream(dfos.getData());
142         } else {
143             return new FileInputStream(dfos.getFile()) {
144                 @SuppressWarnings("ResultOfMethodCallIgnored")
145                 @Override
146                 public void close() throws IOException {
147                     super.close();
148                     dfos.getFile().delete();
149                 }
150             };
151         }
152     }
153 
154     @Nonnull
155     public URL getURL() throws IOException {
156         return getFile().toURI().toURL();
157     }
158 
159     public long getSize() {
160         if (dfos == null) {
161             return fileAttributes.getSize();
162         }
163         if (dfos.isInMemory()) {
164             return dfos.getByteCount();
165         } else {
166             return dfos.getFile().length();
167         }
168     }
169 
170     public boolean isDirectory() {
171         return fileAttributes.isDirectory();
172     }
173 
174     public boolean isExisting() {
175         if (attributes instanceof FileAttributes) {
176             return true;
177         }
178         return getFile().exists();
179     }
180 
181     public boolean isFile() {
182         return fileAttributes.isRegularFile();
183     }
184 
185     @Nonnull
186     public PlexusIoResourceAttributes getAttributes() {
187         return attributes;
188     }
189 
190     @Nonnull
191     public FileAttributes getFileAttributes() {
192         return fileAttributes;
193     }
194 
195     public long getLastModified() {
196         FileTime lastModified = fileAttributes.getLastModifiedTime();
197         if (lastModified != null) {
198             return lastModified.toMillis();
199         }
200         return AttributeUtils.getLastModified(getFile());
201     }
202 
203     @Override
204     public boolean isSymbolicLink() {
205         return getAttributes().isSymbolicLink();
206     }
207 
208     protected DeferredFileOutputStream getDfos() {
209         return dfos;
210     }
211 
212     private static final InputStreamTransformer identityTransformer =
213             AbstractPlexusIoResourceCollection.identityTransformer;
214 }