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.nio.file.Path;
022import java.util.Optional;
023import static java.util.function.Predicate.not;
024import java.util.stream.Collectors;
025import org.jdrupes.builder.api.FileResource;
026import org.jdrupes.builder.api.FileTree;
027import org.jdrupes.builder.api.Project;
028import org.jdrupes.builder.api.Resource;
029import org.jdrupes.builder.api.ResourceFactory;
030import org.jdrupes.builder.api.ResourceType;
031import org.jdrupes.builder.api.Resources;
032
033/// A factory for creating the Core resource objects.
034///
035public class CoreResourceFactory implements ResourceFactory {
036
037    /// Instantiates a new core resource factory.
038    ///
039    @SuppressWarnings("PMD.UnnecessaryConstructor")
040    public CoreResourceFactory() {
041        // Make javadoc happy.
042    }
043
044    /// Checks if the derived interface adds any methods to the
045    /// base interface.
046    ///
047    /// @param <T> the generic type
048    /// @param base the base
049    /// @param derived the derived
050    /// @return true, if successful
051    ///
052    public static <T> boolean addsMethod(
053            Class<T> base, Class<? extends T> derived) {
054        var baseItfs = ResourceType.getAllInterfaces(base)
055            .collect(Collectors.toSet());
056        return ResourceType.getAllInterfaces(derived)
057            .filter(not(baseItfs::contains))
058            .filter(itf -> itf.getDeclaredMethods().length > 0).findAny()
059            .isPresent();
060    }
061
062    @Override
063    @SuppressWarnings({ "unchecked" })
064    public <T extends Resource> Optional<T> newResource(ResourceType<T> type,
065            Project project, Object... args) {
066        if (ResourceType.FileResourceType.isAssignableFrom(type)
067            && type.rawType().getSuperclass() == null
068            && !addsMethod(FileResource.class,
069                (Class<? extends FileResource>) type.rawType())) {
070            return Optional.of((T) DefaultFileResource.createFileResource(
071                (ResourceType<? extends FileResource>) type, (Path) args[0]));
072        }
073        if (Resources.class.isAssignableFrom(type.rawType())
074            && type.rawType().getSuperclass() == null
075            && !addsMethod(Resources.class,
076                (Class<? extends Resources<?>>) type.rawType())) {
077            return Optional.of((T) DefaultResources.createResources(
078                (ResourceType<? extends Resources<?>>) type));
079        }
080        if (FileTree.class.isAssignableFrom(type.rawType())
081            && type.rawType().getSuperclass() == null
082            && !addsMethod(FileTree.class,
083                (Class<? extends FileTree<?>>) type.rawType())) {
084            return Optional.of(
085                (T) DefaultFileTree.createFileTree(
086                    (ResourceType<? extends FileTree<?>>) type,
087                    project, (Path) args[0], (String) args[1]));
088        }
089        if (Resource.class.isAssignableFrom(type.rawType())
090            && type.rawType().getSuperclass() == null
091            && !addsMethod(Resource.class,
092                (Class<? extends Resource>) type.rawType())) {
093            return Optional.of((T) ResourceObject.createResource(
094                (ResourceType<?>) type));
095        }
096        return Optional.empty();
097    }
098
099}