001/* 002 * JDrupes Builder 003 * Copyright (C) 2025 Michael N. Lipp 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <https://www.gnu.org/licenses/>. 017 */ 018 019package org.jdrupes.builder.core; 020 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.OutputStream; 024import java.nio.file.Files; 025import java.nio.file.Path; 026import java.time.Instant; 027import java.util.Objects; 028import java.util.Optional; 029import org.jdrupes.builder.api.BuildException; 030import org.jdrupes.builder.api.ConfigurationException; 031import org.jdrupes.builder.api.FileResource; 032import org.jdrupes.builder.api.ResourceType; 033 034/// A resource that represents a file. 035/// 036public class DefaultFileResource extends ResourceObject 037 implements FileResource { 038 039 private final Path path; 040 041 /// Instantiates a new file resource. 042 /// 043 /// @param type the type 044 /// @param path the path 045 /// 046 @SuppressWarnings("PMD.ConstructorCallsOverridableMethod") 047 protected DefaultFileResource(ResourceType<? extends FileResource> type, 048 Path path) { 049 super(type); 050 if (!path.isAbsolute()) { 051 throw new ConfigurationException().message( 052 "Path must be absolute, is %s", path); 053 } 054 var relPath = Path.of("").toAbsolutePath().relativize(path); 055 name(relPath.equals(Path.of("")) ? "." : relPath.toString()); 056 this.path = path; 057 } 058 059 /// Path. 060 /// 061 /// @return the path 062 /// 063 @Override 064 public Path path() { 065 return path; 066 } 067 068 @Override 069 public Optional<Instant> asOf() { 070 if (!path.toFile().exists()) { 071 return Optional.empty(); 072 } 073 return Optional.of(Instant.ofEpochMilli(path.toFile().lastModified())); 074 } 075 076 @Override 077 public InputStream inputStream() { 078 try { 079 return Files.newInputStream(path); 080 } catch (IOException e) { 081 throw new BuildException().cause(e); 082 } 083 } 084 085 @Override 086 public OutputStream outputStream() { 087 try { 088 return Files.newOutputStream(path); 089 } catch (IOException e) { 090 throw new BuildException().cause(e); 091 } 092 } 093 094 @Override 095 public int hashCode() { 096 final int prime = 31; 097 int result = super.hashCode(); 098 result = prime * result + Objects.hash(path); 099 return result; 100 } 101 102 @Override 103 public boolean equals(Object obj) { 104 if (this == obj) { 105 return true; 106 } 107 if (!super.equals(obj)) { 108 return false; 109 } 110 return (obj instanceof FileResource other) 111 && Objects.equals(path, other.path()); 112 } 113}