001/*
002 * JDrupes Builder
003 * Copyright (C) 2026 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.ext.bnd;
020
021import aQute.bnd.osgi.Processor;
022import io.vavr.Tuple;
023import io.vavr.Tuple2;
024import java.io.IOException;
025import java.nio.file.Files;
026import java.nio.file.Path;
027import java.util.ArrayList;
028import java.util.List;
029import java.util.Map;
030import java.util.Properties;
031import org.jdrupes.builder.api.ConfigurationException;
032import org.jdrupes.builder.api.Project;
033import org.jdrupes.builder.core.AbstractGenerator;
034
035/// A base class for providers using bndlib.
036///
037public abstract class AbstractBndGenerator extends AbstractGenerator {
038
039    private final List<Tuple2<String, String>> instructions = new ArrayList<>();
040
041    /// Initializes a new abstract bnd generator.
042    ///
043    /// @param project the project
044    ///
045    public AbstractBndGenerator(Project project) {
046        super(project);
047    }
048
049    /// Add the instruction specified by key and value.
050    ///
051    /// @param key the key
052    /// @param value the value
053    /// @return the bnd analyzer
054    ///
055    public AbstractBndGenerator instruction(String key, String value) {
056        instructions.add(Tuple.of(key, value));
057        return this;
058    }
059
060    /// Add the given instructions for the analyzer.
061    ///
062    /// @param instructions the instructions
063    /// @return the bnd analyzer
064    ///
065    public AbstractBndGenerator instructions(Map<String, String> instructions) {
066        instructions.forEach(this::instruction);
067        return this;
068    }
069
070    /// Add the instructions from the given bnd (properties) file.
071    ///
072    /// @param bndFile the bnd file
073    /// @return the bnd analyzer
074    ///
075    public AbstractBndGenerator instructions(Path bndFile) {
076        var props = new Properties();
077        try {
078            props.load(Files.newInputStream(bndFile));
079            props.forEach((k, v) -> instruction(k.toString(), v.toString()));
080        } catch (IOException e) {
081            throw new ConfigurationException().message(
082                "Cannot read bnd file %s: %s", bndFile, e).from(this).cause(e);
083        }
084        return this;
085    }
086
087    /// Apply the collected instructions to the given bnd processor.
088    ///
089    /// @param processor the processor
090    ///
091    protected void applyInstructions(Processor processor) {
092        instructions.forEach(t -> processor.setProperty(t._1, t._2));
093    }
094}