FileSystemAudioFile.java

  1. /*
  2.  * *********************************************************************************************************************
  3.  *
  4.  * blueMarine II: Semantic Media Centre
  5.  * http://tidalwave.it/projects/bluemarine2
  6.  *
  7.  * Copyright (C) 2015 - 2021 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
  12.  * the License. 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
  17.  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
  18.  * specific language governing permissions and limitations under the License.
  19.  *
  20.  * *********************************************************************************************************************
  21.  *
  22.  * git clone https://bitbucket.org/tidalwave/bluemarine2-src
  23.  * git clone https://github.com/tidalwave-it/bluemarine2-src
  24.  *
  25.  * *********************************************************************************************************************
  26.  */
  27. package it.tidalwave.bluemarine2.model.impl;

  28. import javax.annotation.Nullable;
  29. import javax.annotation.Nonnegative;
  30. import javax.annotation.Nonnull;
  31. import javax.annotation.concurrent.Immutable;
  32. import java.util.List;
  33. import java.util.Optional;
  34. import java.io.IOException;
  35. import java.nio.file.Files;
  36. import java.nio.file.Path;
  37. import org.springframework.core.io.FileSystemResource;
  38. import org.springframework.core.io.Resource;
  39. import it.tidalwave.util.spi.FinderSupport;import it.tidalwave.util.Id;
  40. import it.tidalwave.util.Key;
  41. import it.tidalwave.util.spi.PriorityAsSupport;
  42. import it.tidalwave.bluemarine2.model.audio.AudioFile;
  43. import it.tidalwave.bluemarine2.model.audio.MusicArtist;
  44. import it.tidalwave.bluemarine2.model.audio.Record;
  45. import it.tidalwave.bluemarine2.model.finder.audio.MusicArtistFinder;
  46. import it.tidalwave.bluemarine2.model.finder.audio.PerformanceFinder;
  47. import it.tidalwave.bluemarine2.model.finder.audio.RecordFinder;
  48. import it.tidalwave.bluemarine2.model.finder.audio.TrackFinder;
  49. import it.tidalwave.bluemarine2.model.spi.NamedEntity;
  50. import it.tidalwave.bluemarine2.model.spi.PathAwareEntity;
  51. import lombok.experimental.Delegate;
  52. import lombok.Getter;
  53. import lombok.RequiredArgsConstructor;
  54. import static java.util.Collections.*;
  55. import static it.tidalwave.role.ui.Displayable._Displayable_;

  56. /***********************************************************************************************************************
  57.  *
  58.  * The default implementation of {@link AudioFile}. It basically does nothing, it just acts as an aggregator of roles.
  59.  *
  60.  * @stereotype  Datum
  61.  *
  62.  * @author  Fabrizio Giudici
  63.  *
  64.  **********************************************************************************************************************/
  65. @Immutable
  66. public class FileSystemAudioFile implements AudioFile, PathAwareEntity
  67.   {
  68.     /*******************************************************************************************************************
  69.      *
  70.      * Minimal implementation of {@link MusicArtist} without search capabilities.
  71.      *
  72.      ******************************************************************************************************************/
  73.     static class ArtistFallback extends NamedEntity implements MusicArtist
  74.       {
  75.         public ArtistFallback (@Nonnull final String displayName)
  76.           {
  77.             super(displayName);
  78.           }

  79.         @Override @Nonnull
  80.         public TrackFinder findTracks()
  81.           {
  82.             throw new UnsupportedOperationException("Not supported yet."); // FIXME
  83.           }

  84.         @Override @Nonnull
  85.         public RecordFinder findRecords()
  86.           {
  87.             throw new UnsupportedOperationException("Not supported yet."); // FIXME
  88.           }

  89.         @Override @Nonnull
  90.         public PerformanceFinder findPerformances()
  91.           {
  92.             throw new UnsupportedOperationException("Not supported yet."); // FIXME
  93.           }

  94.         @Override
  95.         public int getType()
  96.           {
  97.             throw new UnsupportedOperationException("Not supported yet."); // FIXME
  98.           }

  99.         @Override @Nonnull
  100.         public Id getId()
  101.           {
  102.             throw new UnsupportedOperationException("Not supported yet."); // FIXME
  103.           }

  104.         @Override @Nonnull
  105.         public Optional<Id> getSource()
  106.           {
  107.             return Optional.of(Id.of("embedded")); // FIXME
  108.           }
  109.       }

  110.     /*******************************************************************************************************************
  111.      *
  112.      *
  113.      *
  114.      ******************************************************************************************************************/
  115.     @RequiredArgsConstructor
  116.     static class ArtistFallbackFinder extends FinderSupport<MusicArtist, MusicArtistFinder> implements MusicArtistFinder
  117.       {
  118.         private static final long serialVersionUID = 7969726066626602758L;

  119.         @Nonnull
  120.         private final Metadata metadata;

  121.         @Nonnull
  122.         private final Key<String> metadataKey;

  123.         public ArtistFallbackFinder (@Nonnull final ArtistFallbackFinder other, @Nonnull final Object override)
  124.           {
  125.             super(other, override);
  126.             final ArtistFallbackFinder source = getSource(ArtistFallbackFinder.class, other, override);
  127.             this.metadata = source.metadata;
  128.             this.metadataKey = source.metadataKey;
  129.           }

  130.         @Override @Nonnull
  131.         protected List<? extends MusicArtist> computeNeededResults()
  132.           {
  133.             return metadata.get(metadataKey).map(artistName -> List.of(new ArtistFallback(artistName))).orElse(emptyList());
  134.           }

  135.         @Override @Nonnull
  136.         public MusicArtistFinder withId (@Nonnull final Id id)
  137.           {
  138.             throw new UnsupportedOperationException("Not supported yet."); // FIXME
  139.           }

  140.         @Override @Nonnull
  141.         public MusicArtistFinder makerOf (@Nonnull final Id entityId)
  142.           {
  143.             throw new UnsupportedOperationException("Not supported yet."); // FIXME
  144.           }

  145.         @Override @Nonnull
  146.         public MusicArtistFinder importedFrom (@Nonnull final Optional<Id> optionalSource)
  147.           {
  148.             return optionalSource.map(this::importedFrom).orElse(this);
  149.           }

  150.         @Override @Nonnull
  151.         public MusicArtistFinder importedFrom (@Nonnull final Id source)
  152.           {
  153.             throw new UnsupportedOperationException("Not supported yet."); // FIXME
  154.           }

  155.         @Override @Nonnull
  156.         public MusicArtistFinder withFallback (@Nonnull final Optional<Id> optionalFallback)
  157.           {
  158.             return optionalFallback.map(this::withFallback).orElse(this);
  159.           }

  160.         @Override @Nonnull
  161.         public MusicArtistFinder withFallback (@Nonnull final Id fallback)
  162.           {
  163.             throw new UnsupportedOperationException("Not supported yet."); // FIXME
  164.           }
  165.       }

  166.     @Getter @Nonnull
  167.     private final Path path;

  168.     @Getter @Nonnull
  169.     private final Path relativePath;

  170.     @Nonnull
  171.     private final PathAwareEntity parent;

  172.     @Nullable
  173.     private Metadata metadata;

  174.     @Delegate
  175.     private final PriorityAsSupport asSupport = new PriorityAsSupport(this);

  176.     public FileSystemAudioFile (@Nonnull final Path path,
  177.                                 @Nonnull final PathAwareEntity parent,
  178.                                 @Nonnull final Path basePath)
  179.       {
  180.         this.path = path;
  181.         this.parent = parent;
  182.         this.relativePath = basePath.relativize(path);
  183.       }

  184.     @Override @Nonnull
  185.     public Id getId()
  186.       {
  187.         return Id.of(path.toString());
  188.       }

  189.     @Override @Nonnull
  190.     public Optional<PathAwareEntity> getParent()
  191.       {
  192.         return Optional.of(parent);
  193.       }


  194.     @Override @Nonnull
  195.     public Optional<Resource> getContent()
  196.       throws IOException
  197.       {
  198.         return Files.exists(path) ? Optional.of(new FileSystemResource(path.toFile())) : Optional.empty();
  199.       }

  200.     @Override @Nonnegative
  201.     public long getSize()
  202.       throws IOException
  203.       {
  204.         return Files.size(path);
  205.       }

  206.     @Override @Nonnull
  207.     public synchronized Metadata getMetadata()
  208.       {
  209.         if (metadata == null)
  210.           {
  211.             metadata = AudioMetadataFactory.loadFrom(path);
  212.           }

  213.         return metadata;
  214.       }

  215.     @Override @Nonnull
  216.     public MusicArtistFinder findComposers()
  217.       {
  218.         // FIXME: when present, should use a Repository finder
  219.         return new ArtistFallbackFinder(getMetadata(), Metadata.COMPOSER);
  220.       }

  221.     @Override @Nonnull
  222.     public MusicArtistFinder findMakers()
  223.       {
  224.         // FIXME: when present, should use a Repository finder
  225.         return new ArtistFallbackFinder(getMetadata(), Metadata.ARTIST);
  226.       }

  227.     @Override @Nonnull
  228.     public AudioFile getAudioFile()
  229.       {
  230.         return this;
  231.       }

  232.     @Override @Nonnull
  233.     public Optional<Record> getRecord()
  234.       {
  235.             // FIXME: check - parent should be always present - correct?
  236.         return getParent().map(parent -> new NamedRecord(parent.as(_Displayable_).getDisplayName()));
  237.       }

  238.     @Override @Nonnull
  239.     public String toString()
  240.       {
  241.         return String.format("FileSystemAudioFile(%s)", relativePath);
  242.       }
  243.   }