FileOutputBuilder.java

package io.jstach.rainbowgum.file;

import io.jstach.rainbowgum.LogProperties;
import io.jstach.rainbowgum.LogProperty;

/**
 * Builder to create {@link io.jstach.rainbowgum.LogProvider<io.jstach.rainbowgum.file.FileOutput> }.
 * Creates a file output provider. Deferred as a <code>LogProvider</code> (rather than
 * building the file output directly) so that config - in particular the alerts config
 * offers - is available to pass into the concrete output's constructor instead of
 * only reaching it later through the output's start call.
 * <table class="table">
 * <caption><strong>Properties retrieved from LogProperties</strong></caption>
 * <tr>
 * <th>Property Pattern</th>
 * <th>Type</th>
 * <th>Required</th>
 * <th>Default</th>
 * <th>Description</th>
 * </tr>
 * <tr>
 * <td><code>{@value PROPERTY_fileName }</code></td>
 * <td><code>String</code></td>
 * <td><code>false</code></td>
 * <td><code>null</code></td>
 * <td>File name.</td>
 * </tr>
 * <tr>
 * <td><code>{@value PROPERTY_append }</code></td>
 * <td><code>Boolean</code></td>
 * <td><code>false</code></td>
 * <td><code>null</code></td>
 * <td>Whether or not to append to existing file.</td>
 * </tr>
 * <tr>
 * <td><code>{@value PROPERTY_prudent }</code></td>
 * <td><code>Boolean</code></td>
 * <td><code>false</code></td>
 * <td><code>null</code></td>
 * <td>Logback prudent mode where files are locked on each write.</td>
 * </tr>
 * <tr>
 * <td><code>{@value PROPERTY_bufferSize }</code></td>
 * <td><code>String (converted)</code></td>
 * <td><code>true</code></td>
 * <td>{@link io.jstach.rainbowgum.file.FileOutput#DEFAULT_BUFFER_SIZE }</td>
 * <td>Buffer size, in {@link DataSize#parse(String)} format when set by property, e.g. {@code 8KB}. Zero means unbuffered. Must be at most {@value Integer#MAX_VALUE} bytes.</td>
 * </tr>
 * </table>
 */
public final class FileOutputBuilder implements io.jstach.rainbowgum.LogBuilder<FileOutputBuilder,io.jstach.rainbowgum.LogProvider<io.jstach.rainbowgum.file.FileOutput>> {

	/**
	 * The properties to be retrieved from config will have
	 * this prefix.
	 */
	static final String PROPERTY_PREFIX = "logging.appender.{name}.output.file.";
	
	/**
	 * <code>{@value #PROPERTY_fileName } = java.lang.String</code> File name.
	 */
	static final String PROPERTY_fileName = PROPERTY_PREFIX + "fileName";
	/**
	 * <code>{@value #PROPERTY_append } = java.lang.Boolean</code> Whether or not to append to existing file.
	 */
	static final String PROPERTY_append = PROPERTY_PREFIX + "append";
	/**
	 * <code>{@value #PROPERTY_prudent } = java.lang.Boolean</code> Logback prudent mode where files are locked on each write.
	 */
	static final String PROPERTY_prudent = PROPERTY_PREFIX + "prudent";
	/**
	 * <code>{@value #PROPERTY_bufferSize } = io.jstach.rainbowgum.file.DataSize</code> Buffer size, in {@link DataSize#parse(String)} format when set by property, e.g. {@code 8KB}. Zero means unbuffered. Must be at most {@value Integer#MAX_VALUE} bytes.
	 */
	static final String PROPERTY_bufferSize = PROPERTY_PREFIX + "bufferSize";
	
	private final String propertyPrefix;
	final String property_fileName;
	final String property_append;
	final String property_prudent;
	final String property_bufferSize;
	
	private final java.lang.String name;
	private java.net.@org.jspecify.annotations.Nullable URI uri;
	private java.lang.@org.jspecify.annotations.Nullable String fileName = null;
	private java.lang.@org.jspecify.annotations.Nullable Boolean append = null;
	private java.lang.@org.jspecify.annotations.Nullable Boolean prudent = null;
	private io.jstach.rainbowgum.file.DataSize bufferSize = io.jstach.rainbowgum.file.FileOutput.DEFAULT_BUFFER_SIZE;
	
	/**
	 * Create a builder for {@code io.jstach.rainbowgum.LogProvider<io.jstach.rainbowgum.file.FileOutput> }.
	 * @param name will fill <code>{name}</code> in <code>logging.appender.{name}.output.file.</code>. Name of output not file name.
	 */
	public FileOutputBuilder(
			java.lang.String name
			) {
		try {
			java.util.Map<String,String> prefixParameters = java.util.Map.of(
					"name", name
				);
			this.propertyPrefix = LogProperties.interpolateKey(PROPERTY_PREFIX, prefixParameters);
			this.name = name;
			property_fileName = LogProperties.interpolateKey(PROPERTY_fileName, prefixParameters);
			property_append = LogProperties.interpolateKey(PROPERTY_append, prefixParameters);
			property_prudent = LogProperties.interpolateKey(PROPERTY_prudent, prefixParameters);
			property_bufferSize = LogProperties.interpolateKey(PROPERTY_bufferSize, prefixParameters);
		}
		catch (IllegalArgumentException e) {
			throw LogProperty.ValidationException.of(this.getClass(), e);
		}
	}


	/**
	 * Sets uri.
	 * File uri, set by the appender from its <code>output.uri</code>.
	 * Default is <code>null</code>.
	 * @param uri not configurable through properties File uri, set by the appender from its <code>output.uri</code>.
	 * @return this builder.
	 */
	public FileOutputBuilder uri(java.net.@org.jspecify.annotations.Nullable URI uri) {
		this.uri = uri;
		return this;
	}

	
	/**
	 * Sets fileName.
	 * File name.
	 * Default is <code>null</code>.
	 * @param fileName <code>{@value #PROPERTY_fileName } = java.lang.String</code> File name.
	 * @return this builder.
	 */
	public FileOutputBuilder fileName(java.lang.@org.jspecify.annotations.Nullable String fileName) {
		this.fileName = fileName;
		return this;
	}
	
	/**
	 * Sets append.
	 * Whether or not to append to existing file.
	 * Default is <code>null</code>.
	 * @param append <code>{@value #PROPERTY_append } = java.lang.Boolean</code> Whether or not to append to existing file.
	 * @return this builder.
	 */
	public FileOutputBuilder append(java.lang.@org.jspecify.annotations.Nullable Boolean append) {
		this.append = append;
		return this;
	}
	
	/**
	 * Sets prudent.
	 * Logback prudent mode where files are locked on each write.
	 * Default is <code>null</code>.
	 * @param prudent <code>{@value #PROPERTY_prudent } = java.lang.Boolean</code> Logback prudent mode where files are locked on each write.
	 * @return this builder.
	 */
	public FileOutputBuilder prudent(java.lang.@org.jspecify.annotations.Nullable Boolean prudent) {
		this.prudent = prudent;
		return this;
	}
	
	/**
	 * Sets <strong>required</strong> bufferSize.
	 * Buffer size, in {@link DataSize#parse(String)} format when set by property, e.g. {@code 8KB}. Zero means unbuffered. Must be at most {@value Integer#MAX_VALUE} bytes.
	 * Default is {@link io.jstach.rainbowgum.file.FileOutput#DEFAULT_BUFFER_SIZE }.
	 * @param bufferSize <code>{@value #PROPERTY_bufferSize } = io.jstach.rainbowgum.file.DataSize</code> Buffer size, in {@link DataSize#parse(String)} format when set by property, e.g. {@code 8KB}. Zero means unbuffered. Must be at most {@value Integer#MAX_VALUE} bytes.
	 * @return this builder.
	 */
	public FileOutputBuilder bufferSize(io.jstach.rainbowgum.file.DataSize bufferSize) {
		this.bufferSize = bufferSize;
		return this;
	}
	
	/**
	 * Creates {@code io.jstach.rainbowgum.LogProvider<io.jstach.rainbowgum.file.FileOutput> } from this builder.
	 * @return {@code io.jstach.rainbowgum.LogProvider<io.jstach.rainbowgum.file.FileOutput> }.
	 */
	public io.jstach.rainbowgum.LogProvider<io.jstach.rainbowgum.file.FileOutput> build() {
		try {
			return io.jstach.rainbowgum.file.FileOutput.of(
					this.name
					, this.uri
					, this.fileName
					, this.append
					, this.prudent
					, io.jstach.rainbowgum.LogProperty.require(property_bufferSize, this.bufferSize)
					);
		}
		catch (IllegalArgumentException | LogProperty.PropertyMissingException e) {
			throw LogProperty.ValidationException.of(this.getClass(), e);
		}
	}
	
	@Override
	public FileOutputBuilder fromProperties(LogProperties properties) {
		var __v = LogProperty.Validator.of(this.getClass());
		var _fileName = properties.forKey(property_fileName).ofString().or(this.fileName).validateIfError(__v);
		var _append = properties.forKey(property_append).ofBoolean().or(this.append).validateIfError(__v);
		var _prudent = properties.forKey(property_prudent).ofBoolean().or(this.prudent).validateIfError(__v);
		var _bufferSize = properties.forKey(property_bufferSize).ofString().map(_v -> io.jstach.rainbowgum.file.FileOutput.parseDataSize(_v)).or(this.bufferSize).validate(__v);
		__v.validate();
		this.fileName = _fileName.valueOrNull();
		this.append = _append.valueOrNull();
		this.prudent = _prudent.valueOrNull();
		this.bufferSize = _bufferSize.value();
		return this;
	}
	
	/**
	 * The interpolated property prefix: {@value #PROPERTY_PREFIX}.
	 * @return resolved prefix which should end with a "<code>.</code>".
	 */
	@Override
	public String propertyPrefix() {
		return this.propertyPrefix;
	}
	
}