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.time.Instant; 022import java.util.Optional; 023import java.util.SequencedSet; 024import java.util.stream.Stream; 025 026/// Defines a container for a collection of resources. Implementations 027/// must behave as sets (no duplicate entries) and must maintain insertion 028/// order when providing the content through [stream]. 029/// 030/// @param <T> the contained type 031/// 032public interface Resources<T extends Resource> extends Resource { 033 034 /// Adds the given resource. 035 /// 036 /// @param resource the resource 037 /// @return the resources 038 /// 039 Resources<T> add(T resource); 040 041 /// Adds all resources from the given collection. 042 /// 043 /// @param resources the resources to add 044 /// @return the resources 045 /// 046 default Resources<T> addAll(Resources<? extends T> resources) { 047 return addAll(resources.stream()); 048 } 049 050 /// Adds all resources from the given stream. This terminates the given 051 /// stream. 052 /// 053 /// @param resources the resources to add 054 /// @return the resources 055 /// 056 default Resources<T> addAll(Stream<? extends T> resources) { 057 resources.forEach(this::add); 058 return this; 059 } 060 061 /// As of. 062 /// 063 /// @return the instant 064 /// 065 @Override 066 default Optional<Instant> asOf() { 067 return stream() 068 .reduce((newest, next) -> next.isNewerThan(newest) ? next : newest) 069 .map(Resource::asOf).orElse(Optional.empty()); 070 } 071 072 /// Checks if is empty. The default implementation returns 073 /// `get().isEmpty()`. Implementing classes should provide a more 074 /// efficient implementation. 075 /// 076 /// @return true, if is empty 077 /// 078 default boolean isEmpty() { 079 return get().isEmpty(); 080 } 081 082 /// Returns the resources as a [SequencedSet]. 083 /// 084 /// @return the sequenced set 085 /// 086 SequencedSet<T> get(); 087 088 /// Retrieves the resources as a stream. 089 /// 090 /// @return the stream 091 /// 092 default Stream<T> stream() { 093 return get().stream(); 094 } 095 096 /// Clears the contained resources. 097 /// 098 /// @return the resources 099 /// 100 Resources<T> clear(); 101 102 /// Creates a new resource container with elements of the given type. 103 /// 104 /// @param <T> the generic type 105 /// @param type the type 106 /// @return the resources container 107 /// 108 @SuppressWarnings("unchecked") 109 static <T extends Resource> Resources<T> with(Class<T> type) { 110 return (Resources<T>) of(ResourceType.create(Resources.class, type)); 111 } 112 113 /// Creates a new resource container with elements of the given type. 114 /// 115 /// @param <T> the generic type 116 /// @param type the type 117 /// @return the resources container 118 /// 119 static <T extends Resource> Resources<T> with(ResourceType<T> type) { 120 return of(ResourceType.resourceType(Resources.class, type)); 121 } 122 123 /// Creates a new resource container with the specified container 124 /// and elements type. 125 /// 126 /// @param <T> the generic type 127 /// @param type the type 128 /// @return the resources container 129 /// 130 @SuppressWarnings("PMD.ShortMethodName") 131 static <T extends Resource> T of(ResourceType<T> type) { 132 return ResourceFactory.create(type); 133 } 134}