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.Optional;
028import java.util.function.Predicate;
029import org.jdrupes.builder.api.IOResource;
030import org.jdrupes.builder.core.ResourceObject;
031
032/// A temporary resource that is used to store the combined
033/// `META-INF/services/` entries for a given service. The class can be
034/// used for this purpose only. In particular, it does not support
035/// `hashCode` or `equals`.
036///
037public class ServicesEntryResource extends ResourceObject
038        implements IOResource {
039    @SuppressWarnings("PMD.AvoidStringBufferField")
040    private final StringBuilder content = new StringBuilder();
041    private Instant asOf;
042
043    /// Initializes a new services entry resource.
044    ///
045    public ServicesEntryResource() {
046        // Makes javadoc happy.
047    }
048
049    @Override
050    public Optional<Instant> asOf() {
051        return Optional.ofNullable(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.isNewerThan(this)) {
067            asOf = resource.asOf().get();
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}