1 /*
2 * *************************************************************************************************************************************************************
3 *
4 * SteelBlue: DCI User Interfaces
5 * http://tidalwave.it/projects/steelblue
6 *
7 * Copyright (C) 2015 - 2024 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/steelblue-src
22 * git clone https://github.com/tidalwave-it/steelblue-src
23 *
24 * *************************************************************************************************************************************************************
25 */
26 package it.tidalwave.role.ui.example.model;
27
28 import javax.annotation.Nonnegative;
29 import javax.annotation.Nonnull;
30 import javax.annotation.concurrent.Immutable;
31 import java.time.ZoneId;
32 import java.time.ZonedDateTime;
33 import java.util.Collections;
34 import java.util.Comparator;
35 import java.util.List;
36 import java.util.Optional;
37 import java.io.IOException;
38 import java.io.UncheckedIOException;
39 import java.nio.file.Files;
40 import java.nio.file.Path;
41 import java.nio.file.attribute.BasicFileAttributeView;
42 import java.nio.file.attribute.BasicFileAttributes;
43 import java.nio.file.attribute.FileTime;
44 import it.tidalwave.util.As;
45 import it.tidalwave.util.spi.SimpleFinderSupport;
46 import it.tidalwave.role.SimpleComposite;
47 import it.tidalwave.role.ui.Displayable;
48 import lombok.EqualsAndHashCode;
49 import lombok.RequiredArgsConstructor;
50 import lombok.ToString;
51 import lombok.experimental.Delegate;
52 import lombok.extern.slf4j.Slf4j;
53 import static java.util.stream.Collectors.*;
54
55 /***************************************************************************************************************************************************************
56 *
57 * A class that models a file with its attributes and children.
58 *
59 * @author Fabrizio Giudici
60 *
61 **************************************************************************************************************************************************************/
62 @Immutable @EqualsAndHashCode @ToString @Slf4j
63 public class FileEntity implements As, Displayable
64 {
65 @RequiredArgsConstructor
66 public static class FileEntityFinder extends SimpleFinderSupport<FileEntity>
67 {
68 private static final long serialVersionUID = 5780394869213L;
69
70 @Nonnull
71 private final Path path;
72
73 public FileEntityFinder (@Nonnull final FileEntityFinder other, @Nonnull final Object override)
74 {
75 super(other, override);
76 final var source = getSource(FileEntityFinder.class, other, override);
77 this.path = source.path;
78 }
79
80 @Nonnull @Override
81 protected List<FileEntity> computeNeededResults()
82 {
83 try (final var stream = Files.list(path))
84 {
85 return stream.sorted(Comparator.comparing(Path::toString)).map(FileEntity::of).collect(toList());
86 }
87 catch (IOException e)
88 {
89 log.error("While listing directory " + path, e);
90 throw new UncheckedIOException(e);
91 }
92 }
93 }
94
95 /** The path of the file.*/
96 @Nonnull
97 private final Path path;
98
99 /** Support object for implementing {@link As} functions.*/
100 @Delegate
101 private final As delegate;
102
103 /***********************************************************************************************************************************************************
104 * Creates a new instance related to the given path.
105 *
106 * @param path the path
107 **********************************************************************************************************************************************************/
108 // START SNIPPET: constructor
109 private FileEntity (@Nonnull final Path path)
110 {
111 this.path = path;
112 delegate = As.forObject(this, Files.isDirectory(path)
113 ? List.of(SimpleComposite.of(new FileEntityFinder(path)))
114 : Collections.emptyList());
115 }
116 // END SNIPPET: constructor
117
118 /***********************************************************************************************************************************************************
119 * {@return a new instance} related to the given path.
120 * @param path the path
121 **********************************************************************************************************************************************************/
122 // START SNIPPET: constructor
123 @Nonnull
124 public static FileEntity of (@Nonnull final Path path)
125 {
126 return new FileEntity(path);
127 }
128
129 /***********************************************************************************************************************************************************
130 * {@return the display name}. It's a static implementation of the {@link Displayable} role.
131 **********************************************************************************************************************************************************/
132 // START SNIPPET: constructor
133 @Override @Nonnull
134 public String getDisplayName()
135 {
136 return Optional.ofNullable(path.getFileName()).map(Path::toString).orElse("/");
137 }
138
139 /***********************************************************************************************************************************************************
140 * {@return the creation date-time} of the file.
141 * @throws IOException if the file does not exist or cannot be accessed
142 **********************************************************************************************************************************************************/
143 @Nonnull
144 public ZonedDateTime getCreationDateTime()
145 throws IOException
146 {
147 return toZoneDateTime(getBasicFileAttributes().creationTime());
148 }
149
150 /***********************************************************************************************************************************************************
151 * {@return the last access date-time} of the file.
152 * @throws IOException if the file does not exist or cannot be accessed
153 **********************************************************************************************************************************************************/
154 @Nonnull
155 public ZonedDateTime getLastAccessDateTime()
156 throws IOException
157 {
158 return toZoneDateTime(getBasicFileAttributes().lastAccessTime());
159 }
160
161 /***********************************************************************************************************************************************************
162 * {@return the last modified date-time} of the file.
163 * @throws IOException if the file does not exist or cannot be accessed
164 **********************************************************************************************************************************************************/
165 @Nonnull
166 public ZonedDateTime getLastModifiedDateTime()
167 throws IOException
168 {
169 return toZoneDateTime(getBasicFileAttributes().lastModifiedTime());
170 }
171
172 /***********************************************************************************************************************************************************
173 * {@return the size} of the file.
174 * @throws IOException if the file does not exist or cannot be accessed
175 **********************************************************************************************************************************************************/
176 @Nonnegative
177 public long getSize()
178 throws IOException
179 {
180 return Files.size(path);
181 }
182
183 /***********************************************************************************************************************************************************
184 * {@return the basic attributes} of the file.
185 * @throws IOException if the file does not exist or cannot be accessed
186 **********************************************************************************************************************************************************/
187 @Nonnull
188 private BasicFileAttributes getBasicFileAttributes()
189 throws IOException
190 {
191 return Files.getFileAttributeView(path, BasicFileAttributeView.class).readAttributes();
192 }
193
194 /***********************************************************************************************************************************************************
195 *
196 **********************************************************************************************************************************************************/
197 @Nonnull
198 private static ZonedDateTime toZoneDateTime (@Nonnull final FileTime dateTime)
199 {
200 return ZonedDateTime.ofInstant(dateTime.toInstant(), ZoneId.systemDefault());
201 }
202 }