Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>dev.spexx</groupId>
<artifactId>ConfigurationAPI</artifactId>
<version>1.1.0</version>
<version>1.2.0</version>
<packaging>jar</packaging>

<name>ConfigurationAPI</name>
Expand Down
68 changes: 61 additions & 7 deletions src/main/java/dev/spexx/configurationAPI/ConfigurationAPI.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,78 @@
package dev.spexx.configurationAPI;

import dev.spexx.configurationAPI.manager.ConfigManager;
import org.bukkit.plugin.java.JavaPlugin;

/**
* Entry point for the ConfigurationAPI plugin.
*
* <p>This class serves as a minimal bootstrap for the API when used as a plugin.
* In most cases, consumers will interact with the API components directly
* (e.g., {@link dev.spexx.configurationAPI.manager.ConfigManager})
* rather than relying on plugin lifecycle behavior.</p>
* <p>This class acts as a minimal bootstrap when the API is deployed as a Bukkit plugin.</p>
*
* <p>In most cases, consumers should interact directly with API components such as
* {@link ConfigManager} rather than relying on plugin lifecycle behavior.</p>
*
* <h2>Lifecycle</h2>
* <ul>
* <li>{@link #onLoad()} &mdash; called when the plugin is loaded</li>
* <li>{@link #onEnable()} &mdash; called when the plugin is enabled</li>
* <li>{@link #onDisable()} &mdash; called during shutdown</li>
* </ul>
*
* <p>This implementation does not perform any automatic configuration setup.
* It exists primarily to allow the API to function as a standalone plugin if required.</p>
*
* @since 1.0.0
*/
public final class ConfigurationAPI extends org.bukkit.plugin.java.JavaPlugin {
public final class ConfigurationAPI extends JavaPlugin {

/**
* Default constructor.
* Constructs the ConfigurationAPI plugin instance.
*
* <p>Constructs the ConfigurationAPI plugin instance.</p>
* <p>No initialization logic is performed in the constructor.</p>
*
* @since 1.0.4
*/
public ConfigurationAPI() {
}

/**
* Called when the plugin is loaded.
*
* <p>This method is invoked before {@link #onEnable()} and can be used for
* early initialization logic if required.</p>
*
* @since 1.1.0
*/
@Override
public void onLoad() {
// No-op
}

/**
* Called when the plugin is enabled.
*
* <p>This implementation does not automatically initialize any components.
* Consumers are expected to create and manage {@link ConfigManager} instances
* within their own plugins.</p>
*
* @since 1.1.0
*/
@Override
public void onEnable() {
// No-op
}

/**
* Called when the plugin is disabled.
*
* <p>No shutdown logic is required at this level. Individual components
* such as {@link ConfigManager} should be properly shut down by their
* owning plugins.</p>
*
* @since 1.1.0
*/
@Override
public void onDisable() {
// No-op
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,70 @@
/**
* Represents the result of a configuration load or creation operation.
*
* <p>This class encapsulates:</p>
* <p>This class encapsulates the outcome of a configuration-related operation,
* providing structured, non-throwing feedback to the caller.</p>
*
* <p>It contains:</p>
* <ul>
* <li>The {@link ConfigLoadStatus} indicating the outcome</li>
* <li>An optional {@link YamlConfig} if successful</li>
* <li>An optional {@link Exception} if an error occurred</li>
* <li>A {@link ConfigLoadStatus} indicating the result of the operation</li>
* <li>An optional {@link YamlConfig} when the operation succeeds</li>
* <li>An optional {@link Exception} when an error occurs</li>
* </ul>
*
* <p>This allows safe, non-throwing APIs for configuration handling.</p>
* <h2>Usage</h2>
* <p>This class is primarily used by safe APIs that avoid throwing exceptions,
* allowing callers to explicitly handle success and failure cases.</p>
*
* <h2>Consistency Guarantees</h2>
* <ul>
* <li>If {@link #status()} is {@link ConfigLoadStatus#LOADED} or {@link ConfigLoadStatus#CREATED},
* {@link #config()} will be present</li>
* <li>If {@link #status()} is {@link ConfigLoadStatus#IO_ERROR},
* {@link #error()} will be present</li>
* </ul>
*
* @since 1.1.0
*/
public final class ConfigLoadResult {

/**
* Status representing the outcome of the operation.
*/
private final ConfigLoadStatus status;

/**
* Loaded configuration snapshot, if available.
*/
private final YamlConfig config;

/**
* Exception describing a failure, if one occurred.
*/
private final Exception error;

/**
* Creates a new result instance.
* Creates a new {@code ConfigLoadResult}.
*
* <p>This constructor enforces internal consistency between the provided
* {@code status}, {@code config}, and {@code error} values.</p>
*
* <p>The following invariants apply:</p>
* <ul>
* <li>If {@code status} is {@link ConfigLoadStatus#LOADED} or {@link ConfigLoadStatus#CREATED},
* {@code config} must not be {@code null}</li>
* <li>If {@code status} is {@link ConfigLoadStatus#IO_ERROR},
* {@code error} must not be {@code null}</li>
* </ul>
*
* @param status operation status, must not be {@code null}
* @param config resulting configuration, may be {@code null}
* @param error exception if an error occurred, may be {@code null}
* @param config resulting configuration, may be {@code null} depending on {@code status}
* @param error exception if an error occurred, may be {@code null} depending on {@code status}
*
* @throws NullPointerException if {@code status} is {@code null}
* @throws IllegalArgumentException if invariants between {@code status}, {@code config},
* and {@code error} are violated
*
* @since 1.1.0
*/
public ConfigLoadResult(
@NotNull ConfigLoadStatus status,
Expand All @@ -39,30 +80,55 @@ public ConfigLoadResult(
this.status = status;
this.config = config;
this.error = error;

// Enforce invariant: successful states must include a configuration
if ((status == ConfigLoadStatus.LOADED || status == ConfigLoadStatus.CREATED) && config == null) {
throw new IllegalArgumentException("Config must not be null for success status: " + status);
}

// Enforce invariant: error state must include an exception
if (status == ConfigLoadStatus.IO_ERROR && error == null) {
throw new IllegalArgumentException("Error must not be null for IO_ERROR status");
}
}

/**
* Returns the operation status.
* Returns the status of the configuration operation.
*
* @return status value, never {@code null}
* <p>This value indicates whether the operation succeeded, created a new file,
* reused an existing configuration, or failed due to an I/O error.</p>
*
* @return operation status, never {@code null}
*
* @since 1.1.0
*/
public @NotNull ConfigLoadStatus status() {
return status;
}

/**
* Returns the loaded configuration if present.
* Returns the loaded configuration snapshot, if available.
*
* <p>This value is present when the operation completed successfully
* (for example {@link ConfigLoadStatus#LOADED} or {@link ConfigLoadStatus#CREATED}).</p>
*
* @return optional configuration
* @return optional configuration snapshot
*
* @since 1.1.0
*/
public @NotNull Optional<YamlConfig> config() {
return Optional.ofNullable(config);
}

/**
* Returns the error if one occurred.
* Returns the exception associated with a failed operation, if present.
*
* <p>This value is present when {@link #status()} is
* {@link ConfigLoadStatus#IO_ERROR}.</p>
*
* @return optional exception describing the failure
*
* @return optional exception
* @since 1.1.0
*/
public @NotNull Optional<Exception> error() {
return Optional.ofNullable(error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,78 @@
* Represents the result status of a configuration load or creation operation.
*
* <p>This enum is used in conjunction with {@link ConfigLoadResult} to provide
* structured feedback about configuration handling outcomes.</p>
* structured, type-safe feedback about configuration handling outcomes.</p>
*
* <p>Each constant describes a distinct state that may occur when interacting
* with configuration files, including successful operations and failure scenarios.</p>
*
* <h2>Usage</h2>
* <p>This enum is primarily used as part of {@link ConfigLoadResult} to allow
* non-throwing APIs to communicate results without relying on exceptions.</p>
*
* <p>Typical usage pattern:</p>
* <pre>
* ConfigLoadResult result = manager.tryLoad(file);
*
* switch (result.status()) {
* case LOADED -> { ... }
* case CREATED -> { ... }
* case ALREADY_EXISTS -> { ... }
* case IO_ERROR -> { ... }
* }
* </pre>
*
* @since 1.1.0
*/
public enum ConfigLoadStatus {

/**
* Configuration was successfully loaded from disk.
* Indicates that the configuration file was successfully loaded from disk.
*
* <p>This status is returned when an existing file is read and parsed
* without errors.</p>
*
* @since 1.1.0
*/
LOADED,

/**
* Configuration file was newly created and loaded.
* Indicates that the configuration file was newly created and loaded.
*
* <p>This typically occurs when the file did not previously exist and was
* created (for example, via resource extraction or manual creation)
* before being loaded.</p>
*
* @since 1.1.0
*/
CREATED,

/**
* Configuration already existed and was not created again.
* Indicates that the configuration file already existed and was not
* created again.
*
* <p>This status is commonly returned by creation methods when the target
* file is already present on disk.</p>
*
* @since 1.1.0
*/
ALREADY_EXISTS,

/**
* An I/O error occurred during read/write operations.
* Indicates that an I/O error occurred during a configuration operation.
*
* <p>This may include failures such as:</p>
* <ul>
* <li>File read errors</li>
* <li>File write errors</li>
* <li>Permission issues</li>
* <li>Unexpected file system conditions</li>
* </ul>
*
* <p>When this status is returned, the associated exception can be obtained
* from {@link ConfigLoadResult#error()}.</p>
*
* @since 1.1.0
*/
IO_ERROR
}
Loading