FileEntity.java

  1. /*
  2.  * *************************************************************************************************************************************************************
  3.  *
  4.  * SteelBlue: DCI User Interfaces
  5.  * http://tidalwave.it/projects/steelblue
  6.  *
  7.  * Copyright (C) 2015 - 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/steelblue-src
  22.  * git clone https://github.com/tidalwave-it/steelblue-src
  23.  *
  24.  * *************************************************************************************************************************************************************
  25.  */
  26. package it.tidalwave.ui.example.model;

  27. import javax.annotation.Nonnegative;
  28. import jakarta.annotation.Nonnull;
  29. import javax.annotation.concurrent.Immutable;
  30. import java.time.ZoneId;
  31. import java.time.ZonedDateTime;
  32. import java.util.Comparator;
  33. import java.util.List;
  34. import java.util.Optional;
  35. import java.io.IOException;
  36. import java.io.UncheckedIOException;
  37. import java.nio.file.Files;
  38. import java.nio.file.Path;
  39. import java.nio.file.attribute.BasicFileAttributeView;
  40. import java.nio.file.attribute.BasicFileAttributes;
  41. import java.nio.file.attribute.FileTime;
  42. import it.tidalwave.util.As;
  43. import it.tidalwave.util.spi.SimpleFinderSupport;
  44. import it.tidalwave.role.SimpleComposite;
  45. import it.tidalwave.ui.core.role.Displayable;
  46. import lombok.EqualsAndHashCode;
  47. import lombok.RequiredArgsConstructor;
  48. import lombok.ToString;
  49. import lombok.experimental.Delegate;
  50. import lombok.extern.slf4j.Slf4j;
  51. import static java.util.Collections.emptyList;
  52. import static java.util.stream.Collectors.*;

  53. /***************************************************************************************************************************************************************
  54.  *
  55.  * A class that models a file with its attributes and children.
  56.  *
  57.  * @author  Fabrizio Giudici
  58.  *
  59.  **************************************************************************************************************************************************************/
  60. @Immutable @EqualsAndHashCode @ToString @Slf4j
  61. public class FileEntity implements As, Displayable
  62.   {
  63.     @RequiredArgsConstructor
  64.     private static class FileEntityFinder extends SimpleFinderSupport<FileEntity>
  65.       {
  66.         private static final long serialVersionUID = 5780394869213L;

  67.         @Nonnull
  68.         private final Path path;

  69.         public FileEntityFinder (@Nonnull final FileEntityFinder other, @Nonnull final Object override)
  70.           {
  71.             super(other, override);
  72.             final var source = getSource(FileEntityFinder.class, other, override);
  73.             this.path = source.path;
  74.           }

  75.         @Nonnull @Override
  76.         protected List<FileEntity> computeNeededResults()
  77.           {
  78.             try (final var stream = Files.list(path))
  79.               {
  80.                 return stream.sorted(Comparator.comparing(Path::toString)).map(FileEntity::of).collect(toList());
  81.               }
  82.             catch (IOException e)
  83.               {
  84.                 log.error("While listing directory " + path, e);
  85.                 throw new UncheckedIOException(e);
  86.               }
  87.           }
  88.       }

  89.     /** The path of the file.*/
  90.     @Nonnull
  91.     private final Path path;

  92.     /** Support object for implementing {@link As} functions.*/
  93.     @Delegate
  94.     private final As delegate;

  95.     /***********************************************************************************************************************************************************
  96.      * Creates a new instance related to the given path.
  97.      * @param   path    the path
  98.      **********************************************************************************************************************************************************/
  99.     // START SNIPPET: constructor
  100.     private FileEntity (@Nonnull final Path path)
  101.       {
  102.         this.path = path;
  103.         delegate = As.forObject(this, Files.isDirectory(path) ? List.of(SimpleComposite.of(new FileEntityFinder(path))) : emptyList());
  104.       }
  105.     // END SNIPPET: constructor

  106.     /***********************************************************************************************************************************************************
  107.      * {@return a new instance} related to the given path.
  108.      * @param   path    the path
  109.      **********************************************************************************************************************************************************/
  110.     // START SNIPPET: constructor
  111.     @Nonnull
  112.     public static FileEntity of (@Nonnull final Path path)
  113.       {
  114.         return new FileEntity(path);
  115.       }
  116.     // END SNIPPET: constructor

  117.     /***********************************************************************************************************************************************************
  118.      * {@return the display name}. It's a static implementation of the {@link Displayable} role.
  119.      **********************************************************************************************************************************************************/
  120.     @Override @Nonnull
  121.     public String getDisplayName()
  122.       {
  123.         return Optional.ofNullable(path.getFileName()).map(Path::toString).orElse("/");
  124.       }

  125.     /***********************************************************************************************************************************************************
  126.      * {@return the creation date-time} of the file.
  127.      * @throws  IOException if the file does not exist or cannot be accessed
  128.      **********************************************************************************************************************************************************/
  129.     @Nonnull
  130.     public ZonedDateTime getCreationDateTime()
  131.             throws IOException
  132.       {
  133.         return toZoneDateTime(getBasicFileAttributes().creationTime());
  134.       }

  135.     /***********************************************************************************************************************************************************
  136.      * {@return the last access date-time} of the file.
  137.      * @throws  IOException if the file does not exist or cannot be accessed
  138.      **********************************************************************************************************************************************************/
  139.     @Nonnull
  140.     public ZonedDateTime getLastAccessDateTime()
  141.             throws IOException
  142.       {
  143.         return toZoneDateTime(getBasicFileAttributes().lastAccessTime());
  144.       }

  145.     /***********************************************************************************************************************************************************
  146.      * {@return the last modified date-time} of the file.
  147.      * @throws  IOException if the file does not exist or cannot be accessed
  148.      **********************************************************************************************************************************************************/
  149.     @Nonnull
  150.     public ZonedDateTime getLastModifiedDateTime()
  151.             throws IOException
  152.       {
  153.         return toZoneDateTime(getBasicFileAttributes().lastModifiedTime());
  154.       }

  155.     /***********************************************************************************************************************************************************
  156.      * {@return the size} of the file.
  157.      * @throws  IOException if the file does not exist or cannot be accessed
  158.      **********************************************************************************************************************************************************/
  159.     @Nonnegative
  160.     public long getSize()
  161.             throws IOException
  162.       {
  163.         return Files.size(path);
  164.       }

  165.     /***********************************************************************************************************************************************************
  166.      * {@return the basic attributes} of the file.
  167.      * @throws  IOException if the file does not exist or cannot be accessed
  168.      **********************************************************************************************************************************************************/
  169.     @Nonnull
  170.     private BasicFileAttributes getBasicFileAttributes()
  171.             throws IOException
  172.       {
  173.         return Files.getFileAttributeView(path, BasicFileAttributeView.class).readAttributes();
  174.       }

  175.     /***********************************************************************************************************************************************************
  176.      *
  177.      **********************************************************************************************************************************************************/
  178.     @Nonnull
  179.     private static ZonedDateTime toZoneDateTime (@Nonnull final FileTime dateTime)
  180.       {
  181.         return ZonedDateTime.ofInstant(dateTime.toInstant(), ZoneId.systemDefault());
  182.       }
  183.   }