Interface DataStore

All Known Implementing Classes:
JsonStore, MysqlDataStore, SQLiteDataStore

public interface DataStore
Data storage interface.
  • Method Details

    • getStoreType

      String getStoreType()
      Get the type of data storage.
      Returns:
      Data storage type
    • getOperator

      @Deprecated(since="6.3.0", forRemoval=true) <T extends BaseDataEntity<String>> DataOperator<T> getOperator(UltiToolsPlugin plugin, Class<T> dataEntity)
      Deprecated, for removal: This API element is subject to removal in a future version.
      Carries no ownership check of its own (D-14/D-18) -- a DataStore implementation that overrides this method directly must call checkOwnership(UltiToolsPlugin, Class) as its own first statement to get the refusal; the three backends shipped by this framework all do (02-12). Framework- internal callers (UltiToolsPlugin.getDataOperator) already check ownership themselves before calling this. Use getOperator(DataScope, Class).
      Get data operation entity class.
      Type Parameters:
      T - Must inherit BaseDataEntity
      Parameters:
      plugin - Plugin
      dataEntity - Data entity class
      Returns:
      Data operation entity
      Scheduled removal version:
      6.4.0
    • getOperator

      @Deprecated(since="6.3.0", forRemoval=true) default <T extends BaseDataEntity<String>> DataOperator<T> getOperator(File dataFolder, Class<T> dataEntity)
      Deprecated, for removal: This API element is subject to removal in a future version.
      Enforces D-18's ownership check via checkOwnership(java.io.File, Class) as its own first statement -- a DataStore implementation that overrides this method directly must call the same helper to get the refusal; the three backends shipped by this framework all do (02-12). Framework-internal callers (UltiToolsAPI.getDataOperator) already check ownership themselves before calling this. Use getOperator(DataScope, Class).
      Get data operator for an external plugin, scoped to the plugin's own data folder. Refuses outright (D-18) when dataFolder resolves to a registered external plugin's scope that does not own dataEntity, or when dataFolder matches no registered scope at all -- an unresolvable folder fails closed rather than proceeding unchecked (D-15). A DataStore that overrides this method directly (as every backend shipped by this framework does) does not inherit this check; see the @deprecated note.
      Type Parameters:
      T - entity type
      Parameters:
      dataFolder - the external plugin's data folder (e.g., plugins/MyPlugin/)
      dataEntity - data entity class
      Returns:
      data operator
      Throws:
      DataAccessException - if dataFolder matches no registered scope, or matches one that does not own dataEntity
      Since:
      6.2.2
      Scheduled removal version:
      6.4.0
    • checkOwnership

      default void checkOwnership(File dataFolder, Class<?> dataEntity)
      Shared ownership check for the getOperator(java.io.File, Class) legacy overload (D-14/D-18/02-12). Called both by this interface's own default body above and, as the first statement (before any path resolution, cache lookup, or connection-pool creation), by the getOperator(File, Class) override of every backend this framework ships -- so a refused call has not created a pool, a file, or a cache entry as a side effect.

      The reverse lookup only ever registers EXTERNAL scopes (D-18) -- every internal plugin shares the framework's own data folder (DataScope.forPlugin), so that one folder can never be attributed to a single owner by folder alone, and any call reaching here with the framework's own core data folder is refused exactly like any other unregistered folder. Before 02-13 this method exempted the framework's own core data folder from the reverse-lookup refusal, on the reasoning that getOperator(DataScope, Class) needed to reach an INTERNAL scope's own getOperator(File, Class) without being refused a second time. CR-01 (02-REVIEW.md) found that exemption was keyed purely on the value of dataFolder -- and UltiTools#getDataFolder() is public in the published jar, the exact fact D-17's own javadoc names as the reason DataScope had to be unforgeable -- not on any credential or caller identity, so any code sharing the JVM could reach it. On MysqlDataStore this was a genuine, unauthenticated read/write bypass onto another module's real table (there is exactly one global DataSource for the whole server). 02-13's fix: getOperator(DataScope, Class) no longer routes an INTERNAL scope through this method at all -- it resolves directly via an internal, unchecked construction path (see getOperatorUnchecked on the framework's three shipped backends) that never touches this check, so no exemption is needed here anymore.

      Parameters:
      dataFolder - the external plugin's data folder
      dataEntity - data entity class
      Throws:
      DataAccessException - if dataFolder matches no registered scope, or matches one that does not own dataEntity
      Since:
      6.3.0
    • checkOwnership

      default void checkOwnership(UltiToolsPlugin plugin, Class<?> dataEntity)
      Shared ownership check for the getOperator(UltiToolsPlugin, Class) legacy overload (D-14/D-18/02-12), the counterpart to checkOwnership(java.io.File, Class) above for the overload that already carries a UltiToolsPlugin identity directly rather than a File to reverse-resolve. Called by every backend this framework ships as the first statement of their own getOperator(UltiToolsPlugin, Class) override, before any path resolution, cache lookup, or connection-pool creation.

      UltiToolsPlugin exposes no accessor for the DataScope PluginManager mints for it -- only UltiToolsPlugin.setDataScope(com.ultikits.ultitools.manager.DataScope), the injection point, is public -- so this cannot call plugin's own DataScope#owns(Class) directly. It instead consults the same PluginManager#findOwningPlugin(Class) registry DataScope.refusalFor(Class) itself already treats as authoritative for message-building: every scope's owned-entity set is recorded there at minting time (D-19), first-registration- wins on a collision. This project's measured, zero-collision entity population across 21 @Table classes / 17 repositories (02-CONTEXT.md) means "the registry's recorded owner equals the requester's own name" and "the requester's own scope owns the entity" agree in every case this codebase has ever produced; a genuine collision would need UltiToolsPlugin to expose its own DataScope to close fully, which is out of this change's scope (02-12-PLAN.md's file boundary excludes UltiToolsPlugin.java).

      Parameters:
      plugin - the requesting plugin
      dataEntity - data entity class
      Throws:
      DataAccessException - if plugin does not own dataEntity per the registry above
      Since:
      6.3.0
    • getDataSource

      default DataSource getDataSource(DataScope scope)
      Get the JDBC DataSource backing this store for the given scope, needing no entity class up front (a connection pool needs only a JDBC URL).
      Parameters:
      scope - the requesting scope
      Returns:
      the JDBC data source for that scope
      Since:
      6.3.0
    • getOperator

      default <T extends BaseDataEntity<String>> DataOperator<T> getOperator(DataScope scope, Class<T> dataEntity)
      Get a data operator for the entity scope owns, refusing outright when it does not (D-14). The credential is framework-minted and unforgeable (DataScope's constructor and static factories are package-private to manager), so this is the supported path: unlike getOperator(UltiToolsPlugin, Class) and getOperator(java.io.File, Class), it cannot be reached without a scope only the framework can issue, so a caller reaching UltiTools#getDataStore() directly -- public in the published jar -- still cannot obtain an operator for an entity it does not own.

      As of 02-12, the two legacy overloads also refuse an unowned entity -- checkOwnership(UltiToolsPlugin, Class) and checkOwnership(java.io.File, Class) run as the first statement of every backend this framework ships. The distinction this paragraph draws is narrower than it once was, but still real: this method's credential is unforgeable by construction, so calling it correctly is impossible to get wrong. The legacy overloads instead resolve the caller after the fact -- a reverse folder lookup, or an entity-ownership registry consult -- which only protects a caller when the DataStore implementation it reaches has actually wired that resolution in; a hypothetical fourth implementation that overrides getOperator(UltiToolsPlugin, Class) directly without calling checkOwnership(UltiToolsPlugin, Class) would reopen the bypass for that one overload, with nothing but convention (and this javadoc) stopping it. No such gap exists for this method: there is no credential to skip checking, because there is no way to obtain one that was not already checked at minting time.

      02-13 (CR-01): the check above used to delegate to getOperator(java.io.File, Class) for every scope, internal or external -- which for an INTERNAL scope meant reaching checkOwnership(java.io.File, Class)'s now-removed core-folder exemption. It now delegates to getOperatorUnchecked(DataScope, Class) instead, an internal construction path with no ownership check of its own, reachable only after this method's own scope.owns(...) check has already passed -- so the unforgeability guarantee above is no longer contingent on a second method's exemption logic agreeing with it.

      Type Parameters:
      T - Must inherit BaseDataEntity
      Parameters:
      scope - the requesting scope
      dataEntity - data entity class
      Returns:
      data operator for that entity
      Throws:
      DataAccessException - if scope does not own dataEntity
      Since:
      6.3.0
    • getOperatorUnchecked

      default <T extends BaseDataEntity<String>> DataOperator<T> getOperatorUnchecked(DataScope scope, Class<T> dataEntity)
      Internal, unchecked construction path used ONLY by getOperator(DataScope, Class), called after its own scope.owns(...) check has already passed (CR-01, 02-13). Building the actual operator -- path/identity resolution, connection-pool cache, operator cache, transactionManagerFor(...) wiring -- is exactly what the legacy overloads have always done for the internal/external shape scope resolves to; what changed is that getOperator(DataScope, Class) no longer reaches that construction logic via the public, previously ownership-exempt getOperator(java.io.File, Class) overload.

      This member is technically public -- Java gives interface members no narrower visibility -- but it is not reachable as a bypass: nothing outside the manager package can construct a DataScope to pass to it (the same unforgeability getOperator(DataScope, Class) itself relies on), so a caller able to invoke this method at all already holds a scope it could just as validly pass to the checked entry point instead. It is not part of the officially-extensible DataStore contract in the same sense the other members are; the default throws, matching the same "backend does not support this by default" posture getDataSource(DataScope) already uses. The three backends this framework ships each override it.

      Type Parameters:
      T - Must inherit BaseDataEntity
      Parameters:
      scope - the requesting scope, already verified to own dataEntity
      dataEntity - data entity class
      Returns:
      data operator for that entity
      Since:
      6.3.0
    • destroyAllOperators

      void destroyAllOperators()
      Save all possible caches and destroy all data operation classes.