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.java;
020
021import java.io.File;
022import java.nio.file.Path;
023import java.util.stream.Stream;
024import org.jdrupes.builder.api.FileTree;
025import org.jdrupes.builder.api.Project;
026import org.jdrupes.builder.api.Resource;
027import org.jdrupes.builder.api.ResourceRequest;
028import org.jdrupes.builder.core.AbstractGenerator;
029import static org.jdrupes.builder.java.JavaTypes.*;
030
031/// Provides [FileTree]s with classes from a given classpath.
032///
033public class ClasspathScanner extends AbstractGenerator {
034
035    private final String path;
036
037    /// Instantiates a new classpath provider. The `path` is a list of
038    /// directories or jar files separated by the system's path separator.
039    /// Relative paths are resolved against the project's directory.
040    ///
041    /// @param project the project
042    /// @param path the path
043    ///
044    public ClasspathScanner(Project project, String path) {
045        super(project);
046        this.path = path;
047    }
048
049    /// Provide [FileTree]s with classes from a given classpath if the
050    /// requested resource is of type 
051    /// [ClasspathElement](javadoc/org/jdrupes/builder/java/ClasspathElement.html).
052    ///
053    /// @param <T> the requested type
054    /// @param requested the requested resources
055    /// @return the stream
056    ///
057    @Override
058    protected <T extends Resource> Stream<T>
059            doProvide(ResourceRequest<T> requested) {
060        // This supports requests for classpath elements only.
061        if (!requested.collects(ClasspathElementType)) {
062            return Stream.empty();
063        }
064
065        // Map special requests ([RuntimeResources], [CompilationResources])
066        // to the base request
067        if (!ClasspathType.rawType().equals(requested.type().rawType())) {
068            return project().from(this)
069                .get(requested.widened(ClasspathType.rawType()));
070        }
071
072        @SuppressWarnings("unchecked")
073        var result = (Stream<T>) Stream.of(path.split(File.pathSeparator))
074            .map(Path::of).map(p -> project().directory().resolve(p)).map(p -> {
075                if (p.toFile().isDirectory()) {
076                    return (ClasspathElement) project().newResource(
077                        ClassTreeType, p.toAbsolutePath());
078                } else {
079                    return (ClasspathElement) project()
080                        .newResource(LibraryJarFileType, p.toAbsolutePath());
081                }
082            }).filter(e -> requested.collects(e.type()));
083        return result;
084    }
085
086}