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.java;
020
021import java.io.ByteArrayInputStream;
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.OutputStream;
025import java.nio.charset.StandardCharsets;
026import java.time.Instant;
027import java.util.function.Predicate;
028import org.jdrupes.builder.api.IOResource;
029import org.jdrupes.builder.core.ResourceObject;
030
031/// A temporary resource that is used to store the combined
032/// `META-INF/services/` entries for a given service. The class can be
033/// used for this purpose only. In particular, it does not support
034/// `hashCode` or `equals`.
035///
036public class ServicesEntryResource extends ResourceObject
037        implements IOResource {
038    @SuppressWarnings("PMD.AvoidStringBufferField")
039    private final StringBuilder content = new StringBuilder();
040    private Instant asOf = Instant.MIN;
041
042    /// Initializes a new services entry resource.
043    ///
044    @SuppressWarnings("PMD.UnnecessaryConstructor")
045    public ServicesEntryResource() {
046        // Makes javadoc happy.
047    }
048
049    @Override
050    public Instant asOf() {
051        return asOf;
052    }
053
054    /// Adds the given resource which must be a `META-INF/services/*`
055    /// entry from a jar.
056    ///
057    /// @param resource the resource
058    /// @throws IOException Signals that an I/O exception has occurred.
059    ///
060    public void add(IOResource resource) throws IOException {
061        try (InputStream toRead = resource.inputStream()) {
062            new String(toRead.readAllBytes(), StandardCharsets.UTF_8)
063                .lines().filter(Predicate.not(String::isBlank))
064                .forEach(l -> content.append(l).append('\n'));
065        }
066        if (resource.asOf().isAfter(asOf)) {
067            asOf = resource.asOf();
068        }
069    }
070
071    @Override
072    public InputStream inputStream() throws IOException {
073        return new ByteArrayInputStream(
074            content.toString().getBytes(StandardCharsets.UTF_8));
075    }
076
077    @Override
078    public OutputStream outputStream() throws IOException {
079        throw new UnsupportedOperationException();
080    }
081
082}