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 }