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.distribution.internal;
020
021import freemarker.template.Configuration;
022import freemarker.template.Template;
023import freemarker.template.TemplateException;
024import freemarker.template.TemplateExceptionHandler;
025import java.io.IOException;
026import java.io.InputStreamReader;
027import java.io.OutputStream;
028import java.io.OutputStreamWriter;
029import java.nio.charset.StandardCharsets;
030import java.util.HashMap;
031import java.util.List;
032import java.util.Locale;
033import java.util.Map;
034import java.util.stream.Collectors;
035import org.jdrupes.builder.api.BuildException;
036
037/// A base class for distribution builders.
038///
039public class DistributionBuilder {
040
041    /// Initializes a new distribution builder.
042    ///
043    protected DistributionBuilder() {
044        // Make javadoc happy
045    }
046
047    /// Base configuration.
048    ///
049    /// @return the configuration
050    ///
051    protected Configuration baseConfiguration() {
052        var fmConfig = new Configuration(Configuration.VERSION_2_3_34);
053        fmConfig.setDefaultEncoding("utf-8");
054        fmConfig.setTemplateExceptionHandler(
055            TemplateExceptionHandler.RETHROW_HANDLER);
056        fmConfig.setLogTemplateExceptions(false);
057        return fmConfig;
058    }
059
060    /// Builds the FreeMarker model.
061    ///
062    /// @param config the configuration
063    /// @param distClassPath the dist class path
064    /// @return the map
065    ///
066    protected Map<String, Object> buildModel(
067            ApplicationConfigurationData config, List<String> distClassPath) {
068        var model = new HashMap<String, Object>();
069        model.put("applicationName", config.executableName());
070        model.put("mainClassName", config.mainClassName());
071        model.put("classpath",
072            distClassPath.stream().collect(Collectors.joining(":")));
073        model.put("optsEnvironmentVar", config.executableName()
074            .toUpperCase(Locale.getDefault())
075            .replaceAll("[^A-Z0-9_]", "_") + "_OPTS");
076        // Fixed, unless we make the bin directory name configurable
077        model.put("appHomeRelativePath", "..");
078        model.put("defaultJvmOpts", config.applicationJvmOpts().stream()
079            .map(s -> "\"" + s + "\"").collect(Collectors.joining(" ")));
080        return model;
081    }
082
083    /// Adds the unix script.
084    ///
085    /// @param out the out
086    /// @param model the model
087    /// @throws IOException Signals that an I/O exception has occurred.
088    ///
089    protected void addUnixScript(OutputStream out, Map<String, Object> model)
090            throws IOException {
091        var fmConfig = baseConfiguration();
092        fmConfig.setInterpolationSyntax(
093            Configuration.SQUARE_BRACKET_INTERPOLATION_SYNTAX);
094        Template template = new Template("unix", new InputStreamReader(
095            getClass().getResourceAsStream(
096                "/org/jdrupes/builder/java/unixStartScript.ftl"),
097            StandardCharsets.UTF_8), fmConfig);
098        try {
099            var writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
100            template.process(model, writer);
101        } catch (TemplateException e) {
102            throw new BuildException().cause(e);
103        }
104    }
105
106    /// Adds the windows bat.
107    ///
108    /// @param out the out
109    /// @param model the model
110    /// @throws IOException Signals that an I/O exception has occurred.
111    ///
112    protected void addWindowsBat(OutputStream out, Map<String, Object> model)
113            throws IOException {
114        var fmConfig = baseConfiguration();
115        Template template = new Template("windows", new InputStreamReader(
116            getClass().getResourceAsStream(
117                "/org/jdrupes/builder/java/windowsStartScript.ftl"),
118            StandardCharsets.UTF_8), fmConfig);
119        try {
120            var writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
121            template.process(model, writer);
122        } catch (TemplateException e) {
123            throw new BuildException().cause(e);
124        }
125    }
126
127}