View Javadoc
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   }