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.api; 020 021import java.util.Optional; 022import java.util.ServiceLoader; 023import java.util.stream.StreamSupport; 024 025/// Defines both an interface for factories that create [Resource]s and 026/// factory methods for invoking an appropriate factory. 027/// 028@SuppressWarnings("PMD.ImplicitFunctionalInterface") 029public interface ResourceFactory { 030 031 /// Returns a new resource with the given type, passing the given 032 /// arguments to the constructor of the resource. The implementation 033 /// uses [ServiceLoader] to find a [ResourceFactory] that creates the 034 /// resource, i.e. that does not return `Optional.empty()` when 035 /// [newResource] is called. 036 /// 037 /// @param <T> the generic resource type 038 /// @param type the resource type 039 /// @param project the project 040 /// @param args the additional arguments 041 /// @return the resource 042 /// 043 static <T extends Resource> T create(ResourceType<T> type, 044 Project project, Object... args) { 045 return StreamSupport.stream( 046 ServiceLoader.load(ResourceFactory.class).spliterator(), true) 047 .map(f -> f.newResource(type, project, args)) 048 .filter(Optional::isPresent).map(Optional::get).findFirst() 049 .orElseThrow( 050 () -> new BuildException("No resource factory for " + type)); 051 } 052 053 /// Short for `create(type, null, args)`. 054 /// 055 /// @param <T> the generic resource type 056 /// @param type the resource type 057 /// @param args the additional arguments 058 /// @return the resource 059 /// 060 static <T extends Resource> T create(ResourceType<T> type, 061 Object... args) { 062 return create(type, null, args); 063 } 064 065 /// Returns a new resource of the given type if the factory instance 066 /// can create it. 067 /// 068 /// @param <T> the generic resource type 069 /// @param type the resource type 070 /// @param project the project 071 /// @param args the additional arguments 072 /// @return the result. `Optional.empty()` if the resource cannot 073 /// be created by the factory instance. 074 /// 075 <T extends Resource> Optional<T> newResource(ResourceType<T> type, 076 Project project, Object... args); 077 078}