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}