Skip to content

Method: getLastAccessDateTime()

1: /*
2: * *************************************************************************************************************************************************************
3: *
4: * blueMarine III: Semantic DAM
5: * http://tidalwave.it/projects/bluemarine3
6: *
7: * Copyright (C) 2024 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *************************************************************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12: * You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17: * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18: *
19: * *************************************************************************************************************************************************************
20: *
21: * git clone https://bitbucket.org/tidalwave/bluemarine3-src
22: * git clone https://github.com/tidalwave-it/bluemarine3-src
23: *
24: * *************************************************************************************************************************************************************
25: */
26: package it.tidalwave.dam.model.io.impl;
27:
28: import jakarta.annotation.Nonnull;
29: import java.time.ZoneId;
30: import java.time.ZonedDateTime;
31: import java.util.List;
32: import java.util.Objects;
33: import java.util.Optional;
34: import java.util.function.Predicate;
35: import java.util.stream.StreamSupport;
36: import java.io.IOException;
37: import java.io.UncheckedIOException;
38: import java.nio.file.Files;
39: import java.nio.file.Path;
40: import java.nio.file.attribute.BasicFileAttributeView;
41: import java.nio.file.attribute.BasicFileAttributes;
42: import java.nio.file.attribute.FileTime;
43: import java.nio.file.spi.FileSystemProvider;
44: import it.tidalwave.dam.model.MimeType;
45: import it.tidalwave.dam.model.io.FileEntity;
46: import it.tidalwave.dam.model.spi.EntitySupport;
47: import it.tidalwave.util.spi.SimpleFinderSupport;
48: import it.tidalwave.role.SimpleComposite;
49: import lombok.EqualsAndHashCode;
50: import lombok.Getter;
51: import lombok.RequiredArgsConstructor;
52: import lombok.ToString;
53: import lombok.extern.slf4j.Slf4j;
54: import static java.util.Collections.emptyList;
55: import static java.util.Comparator.comparing;
56: import static lombok.AccessLevel.PRIVATE;
57:
58: /***************************************************************************************************************************************************************
59: *
60: * The default implementation of {@link FileEntity}.
61: *
62: * @author Fabrizio Giudici
63: *
64: **************************************************************************************************************************************************************/
65: // @Immutable FIXME
66: @Getter @EqualsAndHashCode(of="path", callSuper = false) @ToString(of = "path") @Slf4j
67: public class DefaultFileEntity extends EntitySupport implements FileEntity
68: {
69: @RequiredArgsConstructor(access = PRIVATE) @SuppressWarnings("serial")
70: private static class ChildrenFinder extends SimpleFinderSupport<FileEntity>
71: {
72: @Nonnull
73: private final FileSystemProvider fsProvider;
74:
75: @Nonnull
76: private final Path path;
77:
78: @Nonnull
79: private final Predicate<FileEntity> filter;
80:
81: /** {@link SimpleFinderSupport}'s special constructor. */
82: public ChildrenFinder (@Nonnull final ChildrenFinder other, @Nonnull final Object override)
83: {
84: super(other, override);
85: final var source = getSource(ChildrenFinder.class, other, override);
86: this.fsProvider = source.fsProvider;
87: this.path = source.path;
88: this.filter = source.filter;
89: }
90:
91: @Override @Nonnull
92: protected List<FileEntity> computeNeededResults()
93: {
94: try (final var dirStream = fsProvider.newDirectoryStream(path, p -> true);
95: final var stream = StreamSupport.stream(dirStream.spliterator(), false))
96: {
97: return stream.map(p -> FileEntity.of(p, filter)).filter(filter).sorted(comparing(f -> f.getPath().toString())).toList();
98: }
99: catch (IOException e)
100: {
101: log.error("While listing directory " + path, e);
102: throw new UncheckedIOException(e);
103: }
104: }
105: }
106:
107: @Nonnull
108: private final FileSystemProvider fileSystemProvider;
109:
110: /** The path of the file.*/
111: @Nonnull
112: private final Path path;
113:
114: /***********************************************************************************************************************************************************
115: * Creates a new instance related to the given path.
116: * @param path the path
117: * @param filter a predicate to filter children
118: **********************************************************************************************************************************************************/
119: public DefaultFileEntity (@Nonnull final Path path, @Nonnull final Predicate<FileEntity> filter)
120: {
121: this(path, filter, path.getFileSystem().provider());
122: }
123:
124: /***********************************************************************************************************************************************************
125: * Creates a new instance related to the given path. This variant is for testing.
126: * @param path the path
127: * @param filter a predicate to filter children
128: * @param fsProvider the file system provider
129: **********************************************************************************************************************************************************/
130: protected DefaultFileEntity (@Nonnull final Path path, @Nonnull final Predicate<FileEntity> filter, @Nonnull final FileSystemProvider fsProvider)
131: {
132: super(Files.isDirectory(path) ? List.of(SimpleComposite.of(new ChildrenFinder(fsProvider, path, filter))) : emptyList());
133: this.fileSystemProvider = fsProvider;
134: this.path = path;
135: }
136:
137: /***********************************************************************************************************************************************************
138: * {@inheritDoc}
139: **********************************************************************************************************************************************************/
140: @Override @Nonnull
141: public String getDisplayName()
142: {
143: return Optional.ofNullable(path.getFileName()).map(Path::toString).orElse("/");
144: }
145:
146: /***********************************************************************************************************************************************************
147: * {@inheritDoc}
148: **********************************************************************************************************************************************************/
149: @Override @Nonnull
150: public ZonedDateTime getCreationDateTime()
151: throws IOException
152: {
153: return toZoneDateTime(getBasicFileAttributes().creationTime());
154: }
155:
156: /***********************************************************************************************************************************************************
157: * {@inheritDoc}
158: **********************************************************************************************************************************************************/
159: @Override @Nonnull
160: public ZonedDateTime getLastAccessDateTime()
161: throws IOException
162: {
163: return toZoneDateTime(getBasicFileAttributes().lastAccessTime());
164: }
165:
166: /***********************************************************************************************************************************************************
167: * {@inheritDoc}
168: **********************************************************************************************************************************************************/
169: @Override @Nonnull
170: public ZonedDateTime getLastModifiedDateTime()
171: throws IOException
172: {
173: return toZoneDateTime(getBasicFileAttributes().lastModifiedTime());
174: }
175:
176: /***********************************************************************************************************************************************************
177: * {@inheritDoc}
178: **********************************************************************************************************************************************************/
179: @Override // FIXME @Nonnegative
180: public long getSize()
181: throws IOException
182: {
183: return Files.size(path);
184: }
185:
186: /***********************************************************************************************************************************************************
187: * {@inheritDoc}
188: **********************************************************************************************************************************************************/
189: @Override
190: public boolean isDirectory()
191: {
192: return Files.isDirectory(path);
193: }
194:
195: /***********************************************************************************************************************************************************
196: * {@inheritDoc}
197: **********************************************************************************************************************************************************/
198: @Override
199: public boolean isUnixHiddenFile()
200: {
201: return Objects.requireNonNull(path.getFileName()).toString().startsWith(".");
202: }
203:
204: /***********************************************************************************************************************************************************
205: * {@inheritDoc}
206: **********************************************************************************************************************************************************/
207: @Override @Nonnull
208: public Optional<MimeType> getMimeType()
209: {
210: return EntitySupport.findMimeType(this);
211: }
212:
213: /***********************************************************************************************************************************************************
214: * {@return the basic attributes} of the file.
215: * @throws IOException if the file does not exist or cannot be accessed
216: **********************************************************************************************************************************************************/
217: @Nonnull
218: private BasicFileAttributes getBasicFileAttributes()
219: throws IOException
220: {
221: return Files.getFileAttributeView(path, BasicFileAttributeView.class).readAttributes();
222: }
223:
224: /***********************************************************************************************************************************************************
225: *
226: **********************************************************************************************************************************************************/
227: @Nonnull
228: private static ZonedDateTime toZoneDateTime (@Nonnull final FileTime dateTime)
229: {
230: return ZonedDateTime.ofInstant(dateTime.toInstant(), ZoneId.systemDefault());
231: }
232: }