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 org.jdrupes.builder.api.BuildException;
029import org.jdrupes.builder.api.FileResource;
030import org.jdrupes.builder.api.ResourceType;
031
032/// A resource that represents a file.
033///
034public class DefaultFileResource extends ResourceObject
035        implements FileResource {
036
037    private final Path path;
038
039    /// Instantiates a new file resource.
040    ///
041    /// @param type the type
042    /// @param path the path
043    ///
044    @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
045    protected DefaultFileResource(ResourceType<? extends FileResource> type,
046            Path path) {
047        super(type);
048        if (!path.isAbsolute()) {
049            throw new BuildException("Path must be absolute, is %s", path);
050        }
051        var relPath = Path.of("").toAbsolutePath().relativize(path);
052        name(relPath.equals(Path.of("")) ? "." : relPath.toString());
053        this.path = path;
054    }
055
056    /// Path.
057    ///
058    /// @return the path
059    ///
060    @Override
061    public Path path() {
062        return path;
063    }
064
065    @Override
066    public Instant asOf() {
067        if (!path.toFile().exists()) {
068            return Instant.MIN;
069        }
070        return Instant.ofEpochMilli(path.toFile().lastModified());
071    }
072
073    @Override
074    public InputStream inputStream() throws IOException {
075        return Files.newInputStream(path);
076    }
077
078    @Override
079    public OutputStream outputStream() throws IOException {
080        return Files.newOutputStream(path);
081    }
082
083    @Override
084    public int hashCode() {
085        final int prime = 31;
086        int result = super.hashCode();
087        result = prime * result + Objects.hash(path);
088        return result;
089    }
090
091    @Override
092    public boolean equals(Object obj) {
093        if (this == obj) {
094            return true;
095        }
096        if (!super.equals(obj)) {
097            return false;
098        }
099        return (obj instanceof FileResource other)
100            && Objects.equals(path, other.path());
101    }
102}