java.lang.Object
com.ultikits.ultitools.interfaces.impl.data.mysql.MysqlDataStore
All Implemented Interfaces:
DataStore

public class MysqlDataStore extends Object implements DataStore
MySQL-backed DataStore.

There is exactly one global HikariDataSource for the whole server (constructed once from config.yml's mysql.* settings), so re-scoping does not move any MySQL data -- but the operator cache below is keyed by (requesting identity, entity class), not by entity class alone, so two plugins sharing an entity class no longer share one DataOperator instance and cannot read each other's rows through it (SILENT-04). Neither map is static: DataStoreManager registers exactly one MysqlDataStore instance.

Version:
1.0.0
Author:
wisdomme
  • Field Details

    • dataOperatorMap

      private final Map<MysqlDataStore.OperatorKey,DataOperator<?>> dataOperatorMap
      Operator cache, keyed by (requesting identity, entity class). Not static -- see class javadoc. Deliberately not Lombok-@Getter'd -- it must stay encapsulated, unlike dataSource below which the framework already exposes.
    • dataSource

      private com.zaxxer.hikari.HikariDataSource dataSource
    • transactionManagerMap

      private final Map<String,JdbcTransactionManager> transactionManagerMap
      JdbcTransactionManager cache, keyed by requesting identity -- one manager per plugin container even though every plugin shares the one global dataSource (D-02): contextHolder is a per-instance ThreadLocal (FOUND-04), so two plugins each doing a @Transactional write on MySQL must never cross transaction state, exactly as PluginManager.wireTransactional's own javadoc already documents for the JDBC path. Not static -- same reload-safety reasoning as dataOperatorMap.

      The single seam through which both transactionManagerFor(DataScope) (called by PluginManager.wireTransactional for the AOP interceptor) and getOperator(com.ultikits.ultitools.abstracts.UltiToolsPlugin, java.lang.Class<T>) (below) resolve a manager for the same identity -- computeIfAbsent guarantees the second caller gets back the exact instance the first one built (T-02-TAM-11).

  • Constructor Details

    • MysqlDataStore

      public MysqlDataStore()
  • Method Details

    • getStoreType

      public String getStoreType()
      Description copied from interface: DataStore
      Get the type of data storage.
      Specified by:
      getStoreType in interface DataStore
      Returns:
      Data storage type
    • getOperator

      public <T extends BaseDataEntity<String>> DataOperator<T> getOperator(UltiToolsPlugin plugin, Class<T> dataEntity)
      Description copied from interface: DataStore
      Get data operation entity class.
      Specified by:
      getOperator in interface DataStore
      Type Parameters:
      T - Must inherit BaseDataEntity
      Parameters:
      plugin - Plugin
      dataEntity - Data entity class
      Returns:
      Data operation entity
    • getOperator

      public <T extends BaseDataEntity<String>> DataOperator<T> getOperator(File dataFolder, Class<T> dataEntity)
      Description copied from interface: DataStore
      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.
      Specified by:
      getOperator in interface DataStore
      Type Parameters:
      T - entity type
      Parameters:
      dataFolder - the external plugin's data folder (e.g., plugins/MyPlugin/)
      dataEntity - data entity class
      Returns:
      data operator
    • getOperatorUnchecked

      public <T extends BaseDataEntity<String>> DataOperator<T> getOperatorUnchecked(DataScope scope, Class<T> dataEntity)
      Internal, unchecked construction path (CR-01/CR-03, 02-13): DataStore.getOperator(DataScope, Class)'s default body calls this only after its own scope.owns(...) check has already passed. Resolves scope to the exact same identity identityFor(DataScope) already derives for transactionManagerFor(DataScope) -- internal scopes resolve to the plugin's own name, external scopes to the canonical data-folder path -- so an internal scope's operator cache entry is keyed identically whether reached through here or through getOperator(UltiToolsPlugin, Class).
      Specified by:
      getOperatorUnchecked in interface DataStore
      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
    • getOperatorForIdentity

      private <T extends BaseDataEntity<String>> DataOperator<T> getOperatorForIdentity(String identity, Class<T> dataEntity)
      Shared operator-construction body for all three entry points above, once ownership has already been established by whichever one of them was called. Single-sourced so the operator cache (keyed by (identity, entity)) and the transactionManagerForIdentity wiring are each written in exactly one place.
    • getDataSource

      public DataSource getDataSource(DataScope scope)
      Description copied from interface: DataStore
      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).
      Specified by:
      getDataSource in interface DataStore
      Parameters:
      scope - the requesting scope
      Returns:
      the JDBC data source for that scope
    • transactionManagerFor

      public JdbcTransactionManager transactionManagerFor(DataScope scope)
      Resolves the same per-plugin-container JdbcTransactionManager instance getOperator(com.ultikits.ultitools.abstracts.UltiToolsPlugin, java.lang.Class<T>) wires onto the operators it hands out for scope's own identity -- the seam PluginManager.wireTransactional calls to bind the AOP @Transactional interceptor to it, so a module's data operators and its @Transactional beans share one transaction, not two (T-02-TAM-11), despite every plugin sharing the one global dataSource.
      Parameters:
      scope - the identity token to resolve the manager for
      Returns:
      the shared manager for that scope's identity
    • identityFor

      private static String identityFor(DataScope scope)
      Resolves scope's operator-cache identity, matching whichever legacy getOperator overload the same scope would actually route through: the internal (plugin name) shape when scope is an internal plugin's own scope (its dataFolder is exactly the core framework's own data folder, DataScope.forPlugin's construction -- the same disambiguation JsonStore.identityOf(DataScope) and SQLiteDataStore.dbPathFor(DataScope) use, 02-05), the external (canonical folder path) shape otherwise. Shared by transactionManagerFor(DataScope) and getOperatorUnchecked(DataScope, Class) (02-13) so the two never disagree on identity.
    • transactionManagerForIdentity

      private JdbcTransactionManager transactionManagerForIdentity(String identity)
      Returns the manager for identity, building it on first touch.
    • canonicalPath

      private static String canonicalPath(File dataFolder)
    • destroyAllOperators

      public void destroyAllOperators()
      Description copied from interface: DataStore
      Save all possible caches and destroy all data operation classes.
      Specified by:
      destroyAllOperators in interface DataStore