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.Proxy;
022import java.util.Collections;
023import java.util.LinkedHashSet;
024import java.util.Objects;
025import java.util.Set;
026import java.util.logging.Logger;
027import java.util.stream.Stream;
028import org.jdrupes.builder.api.Proxyable;
029import org.jdrupes.builder.api.Resource;
030import org.jdrupes.builder.api.ResourceType;
031import org.jdrupes.builder.api.Resources;
032
033/// Represents a set of resources. Resources are added by [add].
034/// The [stream] method returns a stream of the added resources.
035/// The [stream] method preserves the order in which the resources
036/// were added.
037///
038/// @param <T> the type of the contained resources
039///
040public class DefaultResources<T extends Resource> extends ResourceObject
041        implements Resources<T> {
042
043    /// The log.
044    protected final Logger log = Logger.getLogger(getClass().getName());
045    private final Set<T> content;
046
047    /// Instantiates a new resource set.
048    ///
049    /// @param type the type of this instance as resource
050    ///
051    protected DefaultResources(ResourceType<?> type) {
052        super(type);
053        content = Collections.synchronizedSet(new LinkedHashSet<>());
054    }
055
056    /* default */ @SuppressWarnings("unchecked")
057    static <T extends Resources<?>> T createResources(ResourceType<T> type) {
058        return (T) Proxy.newProxyInstance(type.rawType().getClassLoader(),
059            new Class<?>[] { type.rawType(), Proxyable.class },
060            new ForwardingHandler(new DefaultResources<>(type)));
061    }
062
063    @Override
064    public Resources<T> add(T resource) {
065        content.add(resource);
066        return this;
067    }
068
069    @Override
070    public boolean isEmpty() {
071        return content.isEmpty();
072    }
073
074    @Override
075    public Stream<T> stream() {
076        return content.stream();
077    }
078
079    @Override
080    public Resources<T> clear() {
081        content.clear();
082        return this;
083    }
084
085    @Override
086    public int hashCode() {
087        final int prime = 31;
088        int result = super.hashCode();
089        result = prime * result + Objects.hash(content);
090        return result;
091    }
092
093    @Override
094    public boolean equals(Object obj) {
095        if (this == obj) {
096            return true;
097        }
098        if (!super.equals(obj)) {
099            return false;
100        }
101        return (obj instanceof DefaultResources<?> other)
102            && Objects.equals(content, other.content);
103    }
104
105    @Override
106    public String toString() {
107        return type().toString() + " (" + asOfLocalized()
108            + ") with " + content.size() + " elements";
109    }
110
111}