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.util.logging.Level;
022import java.util.logging.Logger;
023import java.util.stream.Stream;
024import org.jdrupes.builder.api.BuildContext;
025import org.jdrupes.builder.api.Resource;
026import org.jdrupes.builder.api.ResourceProvider;
027import org.jdrupes.builder.api.ResourceRequest;
028
029/// A base implementation for[ResourceProvider]s.
030///
031public abstract class AbstractProvider implements ResourceProvider {
032
033    /// The log.
034    @SuppressWarnings("PMD.LambdaCanBeMethodReference")
035    // Use first non-anomymous class for logger.
036    protected final Logger log = Logger.getLogger(
037        Stream.iterate((Class<?>) getClass(),
038            c -> c != null, (Class<?> c) -> c.getSuperclass())
039            .filter(c -> !c.isAnonymousClass())
040            .findFirst().get().getName());
041
042    /// Initializes a new abstract provider.
043    ///
044    @SuppressWarnings("PMD.UnnecessaryConstructor")
045    public AbstractProvider() {
046        // Make javadoc happy.
047    }
048
049    /// Checks if the the current thread executes a provider invocation
050    /// from [BuildContext#get]. Generates a warning if the invocation
051    /// is not allowed. Then invokes [#doProvide].
052    ///
053    /// @return true, if allowed
054    ///
055    @Override
056    @SuppressWarnings("PMD.GuardLogStatement")
057    public final <T extends Resource> Stream<T>
058            provide(ResourceRequest<T> requested) {
059        if (!FutureStream.isProviderInvocationAllowed()) {
060            log.log(Level.WARNING, new IllegalStateException(),
061                () -> "Direct invocation of " + this + " is not allowed");
062        }
063        return doProvide(requested);
064    }
065
066    /// Invoked by [#provide] after checking if the invocation is allowed.
067    ///
068    /// @param <T> the generic type
069    /// @param requested the requested
070    /// @return the stream
071    ///
072    protected abstract <T extends Resource> Stream<T>
073            doProvide(ResourceRequest<T> requested);
074
075    @Override
076    public String toString() {
077        return "Provider " + getClass().getSimpleName();
078    }
079}