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