1 package org.codehaus.plexus.components.io.resources;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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.LinkOption;
29 import java.nio.file.attribute.BasicFileAttributes;
30 import java.nio.file.attribute.FileTime;
31 import java.util.Arrays;
32
33 import org.apache.commons.io.IOUtils;
34 import org.apache.commons.io.output.DeferredFileOutputStream;
35 import org.codehaus.plexus.components.io.attributes.AttributeUtils;
36 import org.codehaus.plexus.components.io.attributes.FileAttributes;
37 import org.codehaus.plexus.components.io.attributes.PlexusIoResourceAttributes;
38 import org.codehaus.plexus.components.io.functions.ContentSupplier;
39 import org.codehaus.plexus.components.io.functions.FileSupplier;
40 import org.codehaus.plexus.components.io.functions.HardLinkIdentitySupplier;
41 import org.codehaus.plexus.components.io.functions.InputStreamTransformer;
42 import org.codehaus.plexus.components.io.functions.ResourceAttributeSupplier;
43
44 import static java.util.Objects.requireNonNull;
45
46
47
48
49 public class PlexusIoFileResource extends AbstractPlexusIoResource
50 implements ResourceAttributeSupplier, FileSupplier, HardLinkIdentitySupplier {
51
52 @Nonnull
53 private final File file;
54
55 @Nonnull
56 private final PlexusIoResourceAttributes attributes;
57
58 @Nonnull
59 private final FileAttributes fileAttributes;
60
61 private final ContentSupplier contentSupplier;
62
63 private final boolean originalContent;
64
65 private final DeferredFileOutputStream dfos;
66
67 protected PlexusIoFileResource(@Nonnull File file, @Nonnull String name, @Nonnull PlexusIoResourceAttributes attrs)
68 throws IOException {
69 this(file, name, attrs, null, null);
70 }
71
72 PlexusIoFileResource(
73 @Nonnull final File file,
74 @Nonnull String name,
75 @Nonnull PlexusIoResourceAttributes attrs,
76 final ContentSupplier contentSupplier,
77 final InputStreamTransformer streamTransformer)
78 throws IOException {
79 this(file, name, attrs, new FileAttributes(file, true), contentSupplier, streamTransformer);
80 }
81
82 PlexusIoFileResource(
83 @Nonnull final File file,
84 @Nonnull String name,
85 @Nonnull PlexusIoResourceAttributes attrs,
86 @Nonnull FileAttributes fileAttributes,
87 final ContentSupplier contentSupplier,
88 final InputStreamTransformer streamTransformer)
89 throws IOException {
90 super(
91 name,
92 fileAttributes.getLastModifiedTime().toMillis(),
93 fileAttributes.getSize(),
94 fileAttributes.isRegularFile(),
95 fileAttributes.isDirectory(),
96 fileAttributes.isRegularFile()
97 || fileAttributes.isDirectory()
98 || fileAttributes.isSymbolicLink()
99 || fileAttributes.isOther());
100 this.file = file;
101 this.attributes = requireNonNull(attrs, "attributes is null for file " + file.getName());
102 this.fileAttributes = requireNonNull(fileAttributes, "fileAttributes is null for file " + file.getName());
103 this.contentSupplier = contentSupplier != null ? contentSupplier : getRootContentSupplier(file);
104
105 boolean hasTransformer = streamTransformer != null && streamTransformer != identityTransformer;
106 InputStreamTransformer transToUse = streamTransformer != null ? streamTransformer : identityTransformer;
107
108 originalContent = contentSupplier == null && !hasTransformer;
109
110 dfos = hasTransformer && file.isFile() ? asDeferredStream(this.contentSupplier, transToUse, this) : null;
111 }
112
113 private static DeferredFileOutputStream asDeferredStream(
114 @Nonnull ContentSupplier supplier, @Nonnull InputStreamTransformer transToUse, PlexusIoResource resource)
115 throws IOException {
116 DeferredFileOutputStream dfos = DeferredFileOutputStream.builder()
117 .setThreshold(5000000)
118 .setPrefix("p-archiver")
119 .get();
120 try (InputStream inputStream = supplier.getContents();
121 InputStream transformed = transToUse.transform(resource, inputStream);
122 DeferredFileOutputStream closeable = dfos) {
123 IOUtils.copy(transformed, dfos);
124 }
125 return dfos;
126 }
127
128 private static ContentSupplier getRootContentSupplier(final File file) {
129 return () -> Files.newInputStream(file.toPath());
130 }
131
132 public static String getName(File file) {
133 return file.getPath().replace('\\', '/');
134 }
135
136
137
138
139 @Nonnull
140 public File getFile() {
141 return file;
142 }
143
144 @Nonnull
145 public InputStream getContents() throws IOException {
146 if (dfos == null) {
147 return contentSupplier.getContents();
148 }
149 if (dfos.isInMemory()) {
150 return new ByteArrayInputStream(dfos.getData());
151 } else {
152 return new FileInputStream(dfos.getFile()) {
153 @SuppressWarnings("ResultOfMethodCallIgnored")
154 @Override
155 public void close() throws IOException {
156 super.close();
157 dfos.getFile().delete();
158 }
159 };
160 }
161 }
162
163 @Nonnull
164 public URL getURL() throws IOException {
165 return getFile().toURI().toURL();
166 }
167
168 public long getSize() {
169 if (dfos == null) {
170 return fileAttributes.getSize();
171 }
172 if (dfos.isInMemory()) {
173 return dfos.getByteCount();
174 } else {
175 return dfos.getFile().length();
176 }
177 }
178
179 public boolean isDirectory() {
180 return fileAttributes.isDirectory();
181 }
182
183 public boolean isExisting() {
184 if (attributes instanceof FileAttributes) {
185 return true;
186 }
187 return getFile().exists();
188 }
189
190 public boolean isFile() {
191 return fileAttributes.isRegularFile();
192 }
193
194 @Nonnull
195 public PlexusIoResourceAttributes getAttributes() {
196 return attributes;
197 }
198
199 @Nonnull
200 public FileAttributes getFileAttributes() {
201 return fileAttributes;
202 }
203
204 public long getLastModified() {
205 FileTime lastModified = fileAttributes.getLastModifiedTime();
206 if (lastModified != null) {
207 return lastModified.toMillis();
208 }
209 return AttributeUtils.getLastModified(getFile());
210 }
211
212 @Override
213 public boolean isSymbolicLink() {
214 return getAttributes().isSymbolicLink();
215 }
216
217
218
219
220
221
222
223
224 @Override
225 public Object getHardLinkIdentity() throws IOException {
226
227 if (!originalContent || getClass() != PlexusIoFileResource.class) {
228 return null;
229 }
230 BasicFileAttributes attrs =
231 Files.readAttributes(file.toPath(), BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
232 if (!attrs.isRegularFile() || attrs.fileKey() == null) {
233 return null;
234 }
235
236 return Arrays.asList(file.toPath().getFileSystem(), attrs.fileKey(), attrs.size(), attrs.lastModifiedTime());
237 }
238
239 protected DeferredFileOutputStream getDfos() {
240 return dfos;
241 }
242
243 private static final InputStreamTransformer identityTransformer =
244 AbstractPlexusIoResourceCollection.identityTransformer;
245 }