Class JsonStore
- All Implemented Interfaces:
DataStore
The operator cache is keyed by (requesting identity, entity class), not by entity class alone
-- two callers resolving to two different identities (two plugins on the plugin path, or two
data folders on the external File path) never share a DataOperator instance
(SILENT-04). Not static: DataStoreManager registers exactly one
JsonStore instance, and instance scoping is what stops the cache from outliving a
/reload.
- Version:
- 1.0.0
- Author:
- wisdomme
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate static final classComposite operator-cache key: the requesting identity (plugin name on the plugin path, canonical data-folder path on the externalFilepath) plus the entity class. -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate final Map<JsonStore.OperatorKey, Cached> Operator cache, keyed by (requesting identity, entity class).private static booleanprivate final Stringprivate final Map<String, JsonTransactionManager> Per-identityJsonTransactionManager, one per requesting identity -- the same identitydataOperatorMapalready keys by -- shared by everySimpleJsonDataOperatorthis store hands out for that identity (02-05, D-03). -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprivate static StringcanonicalPath(File dataFolder) voidSave all possible caches and destroy all data operation classes.private static voidensureTableAnnotation(Class<?> dataEntity) private static StringexternalLocation(File dataFolder, Class<?> dataEntity) The external-plugin storage location shape:<plugin's own data folder>/data/<@Table value>.(package private) voidFlush all cached data operators.(package private) intGet the number of registered data operators.<T extends BaseDataEntity<String>>
DataOperator<T> getOperator(UltiToolsPlugin plugin, Class<T> dataEntity) Get data operation entity class.<T extends BaseDataEntity<String>>
DataOperator<T> getOperator(File dataFolder, Class<T> dataEntity) Get data operator for an external plugin, scoped to the plugin's own data folder.private <T extends BaseDataEntity<String>>
DataOperator<T> getOperatorForIdentity(String identity, String location, Class<T> dataEntity) Shared operator-construction body for all three entry points above, once ownership and the@Tableannotation have already been established by whichever one of them was called.<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 ownscope.owns(...)check has already passed.Get the type of data storage.private static StringidentityOf(DataScope scope) Derives the same identitygetOperator(UltiToolsPlugin, Class)andgetOperator(File, Class)each already resolve forJsonStore.OperatorKey, from aDataScopeinstead of a raw plugin orFile.private voidInitialize the flush scheduler.private StringinternalLocation(String identity, Class<?> dataEntity) The internal-plugin storage location shape:<store location>/<plugin name>/<@Table value>.private static booleanisInternalScope(DataScope scope) Whetherscopeis an internal plugin's own scope -- itsdataFolderis exactly the core framework's own data folder (DataScope.forPlugin's construction).(package private) voidReset the scheduler state.transactionManagerFor(DataScope scope) Resolves (creating on first use) theJsonTransactionManagerforscope, giving the JSON backend a realTransactionManagerso@Transactionalis no longer refused ondatasource.type: json(02-05, D-03).private JsonTransactionManagertransactionManagerFor(String identity) Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface com.ultikits.ultitools.interfaces.DataStore
checkOwnership, checkOwnership, getDataSource, getOperator
-
Field Details
-
dataOperatorMap
Operator cache, keyed by (requesting identity, entity class). Not static -- see class javadoc. -
schedulerInitialized
private static volatile boolean schedulerInitialized -
storeLocation
-
transactionManagers
Per-identityJsonTransactionManager, one per requesting identity -- the same identitydataOperatorMapalready keys by -- shared by everySimpleJsonDataOperatorthis store hands out for that identity (02-05, D-03). Not static, same reasoning asdataOperatorMap.
-
-
Constructor Details
-
JsonStore
-
-
Method Details
-
initScheduler
private void initScheduler()Initialize the flush scheduler. Called lazily when first JsonStore is created. This avoids static initializer issues in test environments.Only the first
JsonStoreinstance in a JVM ever starts the periodic flush task (guarded by thestaticschedulerInitializedflag, matching pre-existing behavior); in production there is exactly oneJsonStoreinstance, so this flushes that instance's own cache, not a shared static one. -
flushAllCaches
void flushAllCaches()Flush all cached data operators. This method is extracted from BukkitRunnable for testability. -
getDataOperatorCount
int getDataOperatorCount()Get the number of registered data operators. Used for testing. -
resetSchedulerState
void resetSchedulerState()Reset the scheduler state. Used for testing. -
getOperator
public <T extends BaseDataEntity<String>> DataOperator<T> getOperator(UltiToolsPlugin plugin, Class<T> dataEntity) Description copied from interface:DataStoreGet data operation entity class.- Specified by:
getOperatorin interfaceDataStore- Type Parameters:
T- Must inheritBaseDataEntity- Parameters:
plugin- PlugindataEntity- 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:DataStoreGet data operator for an external plugin, scoped to the plugin's own data folder. Refuses outright (D-18) whendataFolderresolves to a registered external plugin's scope that does not owndataEntity, or whendataFoldermatches no registered scope at all -- an unresolvable folder fails closed rather than proceeding unchecked (D-15). ADataStorethat overrides this method directly (as every backend shipped by this framework does) does not inherit this check; see the@deprecatednote.- Specified by:
getOperatorin interfaceDataStore- 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 ownscope.owns(...)check has already passed. Branches internal/external exactly likeidentityOf(DataScope)already does fortransactionManagerFor(DataScope)-- an internal scope resolves tointernalLocation(String, Class)keyed on the plugin's own name (never the framework's shared core folder, the collapse regression 02-07 guarded against and CR-01 found reopened as a bypass), an external scope toexternalLocation(File, Class).- Specified by:
getOperatorUncheckedin interfaceDataStore- Type Parameters:
T- Must inheritBaseDataEntity- Parameters:
scope- the requesting scope, already verified to owndataEntitydataEntity- data entity class- Returns:
- data operator for that entity
-
getOperatorForIdentity
private <T extends BaseDataEntity<String>> DataOperator<T> getOperatorForIdentity(String identity, String location, Class<T> dataEntity) Shared operator-construction body for all three entry points above, once ownership and the@Tableannotation have already been established by whichever one of them was called. Single-sourced so the operator cache (keyed by (identity, entity)) and thetransactionManagerFor(...)wiring are each written in exactly one place. -
ensureTableAnnotation
-
internalLocation
The internal-plugin storage location shape:<store location>/<plugin name>/<@Table value>. Shared bygetOperator(UltiToolsPlugin, Class)andgetOperatorUnchecked(DataScope, Class)'s internal branch. -
externalLocation
The external-plugin storage location shape:<plugin's own data folder>/data/<@Table value>. Shared bygetOperator(File, Class)andgetOperatorUnchecked(DataScope, Class)'s external branch. -
isInternalScope
Whetherscopeis an internal plugin's own scope -- itsdataFolderis exactly the core framework's own data folder (DataScope.forPlugin's construction). The same disambiguationidentityOf(DataScope)already uses fortransactionManagerFor(DataScope)(02-05), extracted sogetOperatorUnchecked(DataScope, Class)can also pick the matching location-construction formula, not just the matching identity string. -
transactionManagerFor
Resolves (creating on first use) theJsonTransactionManagerforscope, giving the JSON backend a realTransactionManagerso@Transactionalis no longer refused ondatasource.type: json(02-05, D-03). Called byPluginManager.wireAop's JSON branch, a different package -- public for that reason, even though it is not part of the officially-extensibleDataStorecontract; the actual snapshot mechanics it drives stay package-private onSimpleJsonDataOperator, reached only from inside this class.Shares one instance with every
SimpleJsonDataOperatorgetOperator(com.ultikits.ultitools.abstracts.UltiToolsPlugin, java.lang.Class<T>)hands out for the same identity, so a single@Transactionalmethod's writes across several of that plugin's entities are governed by the same transaction.- Parameters:
scope- the identity token minted for the caller- Returns:
- this store's manager for that caller's identity
-
transactionManagerFor
-
identityOf
Derives the same identitygetOperator(UltiToolsPlugin, Class)andgetOperator(File, Class)each already resolve forJsonStore.OperatorKey, from aDataScopeinstead of a raw plugin orFile.DataScopecarries both a plugin name and a data folder but no explicit internal-vs-external discriminator, so this disambiguates the same wayDataScope.forPlugin(com.ultikits.ultitools.abstracts.UltiToolsPlugin, java.util.Set<java.lang.Class<?>>)itself is built: an internal scope's data folder is always the core UltiTools plugin's own folder (shared by every internal plugin), which no external plugin's own folder can equal. When it matches, the plugin-path identity (DataScope.getPluginName()) is used; otherwise the external-path identity (canonicalPath(java.io.File)) is used. -
canonicalPath
-
destroyAllOperators
public void destroyAllOperators()Description copied from interface:DataStoreSave all possible caches and destroy all data operation classes.- Specified by:
destroyAllOperatorsin interfaceDataStore
-
getStoreType
Description copied from interface:DataStoreGet the type of data storage.- Specified by:
getStoreTypein interfaceDataStore- Returns:
- Data storage type
-