parent
9e5aa7c7a3
commit
f5f776f7cb
273
LICENSE
273
LICENSE
|
@ -47,22 +47,7 @@
|
|||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- Updates - Software Update Management
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Updates
|
||||
Copyright 2021
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
Copyright 2020
|
||||
JetBrains s.r.o. and Kotlin Programming Language contributors
|
||||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- ByteUtilties - Byte manipulation and Unsigned Number Utilities
|
||||
- ByteUtils - Byte manipulation and SHA/xxHash utilities
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/ByteUtilities
|
||||
Copyright 2023
|
||||
|
@ -119,7 +104,7 @@
|
|||
|
||||
- Objenesis -
|
||||
[The Apache Software License, Version 2.0]
|
||||
http://objenesis.org
|
||||
https://github.com/easymock/objenesis
|
||||
Objenesis Team and all contributors
|
||||
|
||||
- MinLog-SLF4J -
|
||||
|
@ -127,6 +112,196 @@
|
|||
https://github.com/EsotericSoftware/minlog
|
||||
Nathan Sweet
|
||||
|
||||
- LZ4 and xxHash - LZ4 compression for Java, based on Yann Collet's work
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/lz4/lz4
|
||||
Copyright 2023
|
||||
Yann Collet
|
||||
Adrien Grand
|
||||
|
||||
- Updates - Software Update Management
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Updates
|
||||
Copyright 2021
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
Copyright 2020
|
||||
JetBrains s.r.o. and Kotlin Programming Language contributors
|
||||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- Json - Lightweight Kotlin/JSON serialization
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Json
|
||||
Copyright 2023
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
- LibGDX Json Utils - Java object graphs, to and from JSON automatically
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
|
||||
Copyright 2011
|
||||
Mario Zechner
|
||||
Nathan Sweet
|
||||
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
Copyright 2020
|
||||
JetBrains s.r.o. and Kotlin Programming Language contributors
|
||||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- Updates - Software Update Management
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Updates
|
||||
Copyright 2021
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
Copyright 2020
|
||||
JetBrains s.r.o. and Kotlin Programming Language contributors
|
||||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- Collections - Collection types and utilities to enhance the default collections.
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Collections
|
||||
Copyright 2023
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
- Bias, BinarySearch -
|
||||
[MIT License]
|
||||
https://git.dorkbox.com/dorkbox/Collections
|
||||
https://github.com/timboudreau/util
|
||||
Copyright 2013
|
||||
Tim Boudreau
|
||||
|
||||
- ConcurrentEntry -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Collections
|
||||
Copyright 2016
|
||||
bennidi
|
||||
dorkbox
|
||||
|
||||
- Collection Utilities (Array, ArrayMap, BooleanArray, ByteArray, CharArray, FloatArray, IdentityMap, IntArray, IntFloatMap, IntIntMap, IntMap, IntSet, LongArray, LongMap, ObjectFloatMap, ObjectIntMap, ObjectMap, ObjectSet, OrderedMap, OrderedSet) -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Collections
|
||||
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
|
||||
Copyright 2011
|
||||
LibGDX
|
||||
Mario Zechner (badlogicgames@gmail.com)
|
||||
Nathan Sweet (nathan.sweet@gmail.com)
|
||||
|
||||
- Predicate -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Collections
|
||||
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
|
||||
Copyright 2011
|
||||
LibGDX
|
||||
Mario Zechner (badlogicgames@gmail.com)
|
||||
Nathan Sweet (nathan.sweet@gmail.com)
|
||||
xoppa
|
||||
|
||||
- Select, QuickSelect -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Collections
|
||||
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
|
||||
Copyright 2011
|
||||
LibGDX
|
||||
Mario Zechner (badlogicgames@gmail.com)
|
||||
Nathan Sweet (nathan.sweet@gmail.com)
|
||||
Jon Renner
|
||||
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
Copyright 2020
|
||||
JetBrains s.r.o. and Kotlin Programming Language contributors
|
||||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- Updates - Software Update Management
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Updates
|
||||
Copyright 2021
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
Copyright 2020
|
||||
JetBrains s.r.o. and Kotlin Programming Language contributors
|
||||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- MinLog - Drop-in replacement for MinLog to log through SLF4j.
|
||||
[BSD 3-Clause License]
|
||||
https://git.dorkbox.com/dorkbox/MinLog-SLF4J
|
||||
https://github.com/EsotericSoftware/minlog
|
||||
Copyright 2023
|
||||
Dorkbox LLC
|
||||
Nathan Sweet
|
||||
Dan Brown
|
||||
|
||||
Extra license information
|
||||
- SLF4J - Simple facade or abstraction for various logging frameworks
|
||||
[MIT License]
|
||||
https://www.slf4j.org
|
||||
Copyright 2023
|
||||
QOS.ch
|
||||
|
||||
- Updates - Software Update Management
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Updates
|
||||
Copyright 2021
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
Copyright 2020
|
||||
JetBrains s.r.o. and Kotlin Programming Language contributors
|
||||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- ObjectPool - Fast, lightweight, and compatible blocking/non-blocking/soft-reference object pool for Java 8+
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/ObjectPool
|
||||
Copyright 2023
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
- kotlinx.coroutines - Library support for Kotlin coroutines with multiplatform support
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/Kotlin/kotlinx.coroutines
|
||||
Copyright 2023
|
||||
JetBrains s.r.o.
|
||||
|
||||
- Conversant Disruptor - Disruptor is the highest performing intra-thread transfer mechanism available in Java.
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/conversant/disruptor
|
||||
Copyright 2023
|
||||
Conversant, Inc
|
||||
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
Copyright 2020
|
||||
JetBrains s.r.o. and Kotlin Programming Language contributors
|
||||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- Updates - Software Update Management
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Updates
|
||||
|
@ -207,25 +382,13 @@
|
|||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- ObjectPool - Fast, lightweight, and compatible blocking/non-blocking/soft-reference object pool for Java 8+
|
||||
- Updates - Software Update Management
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/ObjectPool
|
||||
Copyright 2023
|
||||
https://git.dorkbox.com/dorkbox/Updates
|
||||
Copyright 2021
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
- kotlinx.coroutines - Library support for Kotlin coroutines with multiplatform support
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/Kotlin/kotlinx.coroutines
|
||||
Copyright 2023
|
||||
JetBrains s.r.o.
|
||||
|
||||
- Conversant Disruptor - Disruptor is the highest performing intra-thread transfer mechanism available in Java.
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/conversant/disruptor
|
||||
Copyright 2023
|
||||
Conversant, Inc
|
||||
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
|
@ -233,49 +396,3 @@
|
|||
JetBrains s.r.o. and Kotlin Programming Language contributors
|
||||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- Updates - Software Update Management
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Updates
|
||||
Copyright 2021
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
Copyright 2020
|
||||
JetBrains s.r.o. and Kotlin Programming Language contributors
|
||||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
||||
- MinLog - Drop-in replacement for MinLog to log through SLF4j.
|
||||
[BSD 3-Clause License]
|
||||
https://git.dorkbox.com/dorkbox/MinLog-SLF4J
|
||||
https://github.com/EsotericSoftware/minlog
|
||||
Copyright 2023
|
||||
Dorkbox LLC
|
||||
Nathan Sweet
|
||||
Dan Brown
|
||||
|
||||
Extra license information
|
||||
- SLF4J - Simple facade or abstraction for various logging frameworks
|
||||
[MIT License]
|
||||
https://www.slf4j.org
|
||||
Copyright 2023
|
||||
QOS.ch
|
||||
|
||||
- Updates - Software Update Management
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Updates
|
||||
Copyright 2021
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
- Kotlin -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/JetBrains/kotlin
|
||||
Copyright 2020
|
||||
JetBrains s.r.o. and Kotlin Programming Language contributors
|
||||
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
|
||||
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
|
||||
|
|
|
@ -93,12 +93,12 @@ dependencies {
|
|||
api("org.slf4j:slf4j-api:2.0.7")
|
||||
|
||||
|
||||
api("com.dorkbox:Updates:1.1")
|
||||
|
||||
api("com.dorkbox:ByteUtilities:1.8")
|
||||
api("com.dorkbox:Serializers:2.8")
|
||||
api("com.dorkbox:ObjectPool:4.3")
|
||||
api("com.dorkbox:ByteUtilities:1.13")
|
||||
api("com.dorkbox:Json:1.1")
|
||||
api("com.dorkbox:MinLog:2.5")
|
||||
api("com.dorkbox:ObjectPool:4.3")
|
||||
api("com.dorkbox:Serializers:2.9")
|
||||
api("com.dorkbox:Updates:1.1")
|
||||
|
||||
api("com.esotericsoftware:kryo:5.5.0") {
|
||||
exclude("com.esotericsoftware", "minlog") // we use our own minlog, that logs to SLF4j instead
|
||||
|
@ -114,7 +114,6 @@ dependencies {
|
|||
testImplementation("junit:junit:4.13.2")
|
||||
testImplementation("ch.qos.logback:logback-classic:1.4.5")
|
||||
testImplementation("org.agrona:agrona:1.14.0")
|
||||
|
||||
}
|
||||
|
||||
publishToSonatype {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2021 dorkbox, llc
|
||||
* Copyright 2023 dorkbox, llc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -128,7 +128,9 @@ abstract class Storage(val logger: KLogger) : AutoCloseable {
|
|||
abstract override fun close()
|
||||
|
||||
interface Builder {
|
||||
/** true if the backing storage type uses strings for everything, or false if it uses something else */
|
||||
/**
|
||||
* true if the backing storage type uses strings for everything, or false if it uses something else
|
||||
*/
|
||||
val isStringBased: Boolean
|
||||
|
||||
/**
|
||||
|
@ -178,6 +180,7 @@ abstract class Storage(val logger: KLogger) : AutoCloseable {
|
|||
var serializer: SerializerBytes = defaultSerializer
|
||||
|
||||
var shared = false
|
||||
|
||||
@Volatile
|
||||
var sharedBuild: Storage? = null
|
||||
|
||||
|
@ -278,9 +281,9 @@ abstract class Storage(val logger: KLogger) : AutoCloseable {
|
|||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = onLoad?.hashCode() ?: 0 //lambda
|
||||
result = 31 * result + (onSave?.hashCode() ?: 0) //lambda
|
||||
result = 31 * result + serializer.hashCode() //lambda
|
||||
var result = onLoad.hashCode()
|
||||
result = 31 * result + onSave.hashCode()
|
||||
result = 31 * result + serializer.hashCode()
|
||||
result = 31 * result + shared.hashCode()
|
||||
result = 31 * result + (sharedBuild?.hashCode() ?: 0)
|
||||
result = 31 * result + logger.hashCode()
|
||||
|
@ -445,12 +448,32 @@ abstract class Storage(val logger: KLogger) : AutoCloseable {
|
|||
// * JSON file storage system
|
||||
// */
|
||||
// class Json : Storage.FileBuilder<Json>() {
|
||||
// companion object {
|
||||
// // property files MUST load via strings.
|
||||
// val defaultOnLoad: AccessFunc = { serializer, key, value, load ->
|
||||
// val keyBytes = (key as String).decodeBase58()
|
||||
// val valueBytes = (value as String).decodeBase58()
|
||||
//
|
||||
// val xKey = serializer.deserialize<Any>(keyBytes)!!
|
||||
// val xValue = serializer.deserialize<Any>(valueBytes)
|
||||
// load(xKey, xValue)
|
||||
// }
|
||||
//
|
||||
// val defaultOnSave: AccessFunc = { serializer, key, value, save ->
|
||||
// val xKey = serializer.serialize(key).encodeToBase58String()
|
||||
// val xValue = serializer.serialize(value).encodeToBase58String()
|
||||
// save(xKey, xValue)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private var autoLoad = false
|
||||
//
|
||||
// override var onLoad: AccessFunc = defaultOnLoad
|
||||
// override var onSave: AccessFunc = defaultOnSave
|
||||
//
|
||||
// override fun build(): Storage {
|
||||
// return manageShared {
|
||||
// JsonStore(file.absoluteFile, autoLoad, readOnly, readOnlyViolent, logger,
|
||||
// onLoad, onSave)
|
||||
// JsonStore(file.absoluteFile, autoLoad, readOnly, readOnlyViolent, logger, onLoad, onSave)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2021 dorkbox, llc
|
||||
* Copyright 2023 dorkbox, llc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -15,230 +15,208 @@
|
|||
*/
|
||||
package dorkbox.storage.types
|
||||
|
||||
///**
|
||||
// * JSON property file storage system
|
||||
// */
|
||||
//class JsonStore(
|
||||
// val dbFile: File,
|
||||
// val autoLoad: Boolean,
|
||||
// val readOnly: Boolean,
|
||||
// val readOnlyViolent: Boolean,
|
||||
// logger: KLogger,
|
||||
// val onLoad: ((key: Any, value: Any, load: (key: Any, value: Any) -> Unit) -> Unit)?,
|
||||
// val onSave: ((key: Any, value: Any, save: (key: Any, value: Any) -> Unit) -> Unit)?,
|
||||
//) : Storage(logger) {
|
||||
//
|
||||
// companion object {
|
||||
// private val comparator = Comparator<Any> { o1, o2 -> o1.toString().compareTo(o2.toString()) }
|
||||
// }
|
||||
//
|
||||
// private val thread = Thread { close() }
|
||||
//
|
||||
// @Volatile
|
||||
// private var lastModifiedTime = 0L
|
||||
//
|
||||
// private var output = ByteBufferOutput(64, 65535) // A reasonable max size of an object. We don't want to support it being TOO big
|
||||
// private var input = Input()
|
||||
//
|
||||
// private val loadedProps = ConcurrentHashMap<Any, Any>()
|
||||
//
|
||||
// init {
|
||||
// load()
|
||||
//
|
||||
// // Make sure that the timer is run on shutdown. A HARD shutdown will just POW! kill it, a "nice" shutdown will run the hook
|
||||
// Runtime.getRuntime().addShutdownHook(thread)
|
||||
//
|
||||
// init("Property file storage initialized at: '$dbFile'")
|
||||
// }
|
||||
//
|
||||
// private fun load() {
|
||||
// // if we cannot load, then we create a properties file.
|
||||
// if (!dbFile.canRead() && !dbFile.parentFile.mkdirs() && !dbFile.createNewFile()) {
|
||||
// throw IOException("Cannot create file")
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// synchronized(dbFile) {
|
||||
// FileInputStream(dbFile).use { fileStream ->
|
||||
// val properties = Properties()
|
||||
// properties.load(fileStream)
|
||||
// lastModifiedTime = dbFile.lastModified()
|
||||
//
|
||||
// properties.entries.forEach { (k, v) ->
|
||||
// val key = k
|
||||
// val value = Base64.getDecoder().decode(v as String)
|
||||
//
|
||||
// input.reset()
|
||||
// input.buffer = value
|
||||
//
|
||||
// try {
|
||||
// val valueObject = serializationManager.readFullClassAndObject(input)
|
||||
// if (valueObject != null) {
|
||||
// loadedProps[key] = valueObject
|
||||
// } else {
|
||||
// logger.error("Unable to parse property (file: $dbFile) $key : $value")
|
||||
// }
|
||||
// } catch (e: Exception) {
|
||||
// logger.error("Unable to parse property (file: $dbFile) $key : $value", e)
|
||||
// }
|
||||
// }
|
||||
// properties.clear()
|
||||
// }
|
||||
// }
|
||||
// } catch (e: IOException) {
|
||||
// logger.error("Cannot load properties!", e)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun save() {
|
||||
// if (readOnly) {
|
||||
// // don't accidentally save this!
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // if we cannot save, then we create a NEW properties file. It could have been DELETED out from under us (while in use!)
|
||||
// if (!dbFile.canRead() && !dbFile.parentFile.mkdirs() && !dbFile.createNewFile()) {
|
||||
// throw IOException("Cannot create file")
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// synchronized(dbFile) {
|
||||
// val properties = object : Properties() {
|
||||
// override fun keys(): Enumeration<Any> {
|
||||
// val keysEnum = super.keys()
|
||||
//
|
||||
// val vector = Vector<Any>(size())
|
||||
// while (keysEnum.hasMoreElements()) {
|
||||
// vector.add(keysEnum.nextElement())
|
||||
// }
|
||||
//
|
||||
// vector.sortWith(comparator)
|
||||
// return vector.elements()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// loadedProps.forEach { (key, value) ->
|
||||
// // have to serialize the value
|
||||
// output.reset()
|
||||
// try {
|
||||
// serializationManager.writeFullClassAndObject(output, value)
|
||||
// output.byteBuffer.flip()
|
||||
// val valueEncoded = Base64.getEncoder().encode(output.byteBuffer)
|
||||
// properties[key] = String(valueEncoded.array(), 0, valueEncoded.limit())
|
||||
// } catch (e: Exception) {
|
||||
// logger.error("Unable to save property: $key $value")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// FileOutputStream(dbFile, false).use { fos ->
|
||||
// properties.store(fos, "Storage data, Version: $version")
|
||||
// fos.flush()
|
||||
// properties.clear()
|
||||
// lastModifiedTime = dbFile.lastModified()
|
||||
// }
|
||||
// }
|
||||
// } catch (e: IOException) {
|
||||
// logger.error("Properties cannot save to: $dbFile", e)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun file(): File {
|
||||
// return dbFile
|
||||
// }
|
||||
//
|
||||
// override fun size(): Int {
|
||||
// return loadedProps.size
|
||||
// }
|
||||
//
|
||||
// override fun contains(key: Any): Boolean {
|
||||
// require(key is String) {
|
||||
// "Keys for a json file must be a String"
|
||||
// }
|
||||
//
|
||||
// if (autoLoad) {
|
||||
// // we want to check the last modified time when getting, because if we edit the on-disk file, we want to load those changes
|
||||
// val lastModifiedTime = dbFile.lastModified()
|
||||
// if (this.lastModifiedTime != lastModifiedTime) {
|
||||
// // we want to reload the info
|
||||
// load()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return loadedProps[key] != null
|
||||
// }
|
||||
//
|
||||
// override operator fun <V> get(key: Any): V? {
|
||||
// require(key is String) {
|
||||
// "Keys for a json file must be a String"
|
||||
// }
|
||||
//
|
||||
// if (autoLoad) {
|
||||
// // we want to check the last modified time when getting, because if we edit the on-disk file, we want to load those changes
|
||||
// val lastModifiedTime = dbFile.lastModified()
|
||||
// if (this.lastModifiedTime != lastModifiedTime) {
|
||||
// // we want to reload the info
|
||||
// load()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// val any = loadedProps[key]
|
||||
// if (any != null) {
|
||||
// @Suppress("UNCHECKED_CAST")
|
||||
// return any as V
|
||||
// }
|
||||
//
|
||||
// return null
|
||||
// }
|
||||
//
|
||||
// override operator fun set(key: Any, data: Any?) {
|
||||
// require(key is String) {
|
||||
// "Keys for a json file must be a String"
|
||||
// }
|
||||
//
|
||||
// if (readOnly) {
|
||||
// if (readOnlyViolent) {
|
||||
// throw IOException("Unable to save data in $dbFile for $key : $data")
|
||||
// } else {
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// val hasChanged = if (data == null) {
|
||||
// loadedProps.remove(key) != null
|
||||
// } else {
|
||||
// val prev = loadedProps.put(key, data)
|
||||
// prev !== data
|
||||
// }
|
||||
//
|
||||
// // every time we set info, we want to save it to disk (so the file on disk will ALWAYS be current, and so we can modify it as we choose)
|
||||
// if (hasChanged) {
|
||||
// save()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Deletes all contents of this storage, and if applicable, it's location on disk.
|
||||
// */
|
||||
// override fun deleteAll() {
|
||||
// if (readOnly) {
|
||||
// if (readOnlyViolent) {
|
||||
// throw IOException("Unable to delete all data in $dbFile")
|
||||
// } else {
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// loadedProps.clear()
|
||||
// dbFile.delete()
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Closes this storage (and if applicable, flushes it's content to disk)
|
||||
// */
|
||||
// override fun close() {
|
||||
// Runtime.getRuntime().removeShutdownHook(thread)
|
||||
// save()
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//
|
||||
import dorkbox.json.JsonException
|
||||
import dorkbox.json.OutputType
|
||||
import dorkbox.storage.AccessFunc
|
||||
import dorkbox.storage.Storage
|
||||
import mu.KLogger
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.*
|
||||
|
||||
/**
|
||||
* JSON property file storage system
|
||||
*/
|
||||
class JsonStore(
|
||||
val dbFile: File,
|
||||
val autoLoad: Boolean,
|
||||
val readOnly: Boolean,
|
||||
val readOnlyViolent: Boolean,
|
||||
logger: KLogger,
|
||||
onLoad: AccessFunc,
|
||||
onSave: AccessFunc,
|
||||
) : Storage(logger) {
|
||||
|
||||
companion object {
|
||||
private val comparator = Comparator<Any> { o1, o2 -> o1.toString().compareTo(o2.toString()) }
|
||||
}
|
||||
|
||||
private var version: Long = 0
|
||||
private val thread = Thread { close() }
|
||||
|
||||
private val json = dorkbox.json.Json()
|
||||
|
||||
@Volatile
|
||||
private var lastModifiedTime = 0L
|
||||
|
||||
private val loadedProps = ConcurrentHashMap<Any, Any?>()
|
||||
|
||||
init {
|
||||
json.outputType = OutputType.json
|
||||
|
||||
load()
|
||||
val versionInfo = loadedProps[versionTag]
|
||||
if (versionInfo !is Number) {
|
||||
loadedProps[versionTag] = version
|
||||
} else {
|
||||
setVersion(versionInfo as Long)
|
||||
}
|
||||
|
||||
|
||||
// Make sure that the timer is run on shutdown. A HARD shutdown will just POW! kill it, a "nice" shutdown will run the hook
|
||||
Runtime.getRuntime().addShutdownHook(thread)
|
||||
|
||||
init("Property file storage initialized at: '$dbFile'")
|
||||
}
|
||||
|
||||
private fun load() {
|
||||
// if we cannot load, then we create a properties file.
|
||||
if (!dbFile.canRead() && !dbFile.parentFile.mkdirs() && !dbFile.createNewFile()) {
|
||||
throw IOException("Cannot create file")
|
||||
}
|
||||
|
||||
try {
|
||||
synchronized(dbFile) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val map = json.fromJson(HashMap::class.java, dbFile) as Map<Any, Any?>?
|
||||
map?.forEach { (k,v) ->
|
||||
loadedProps[k] = v
|
||||
}
|
||||
lastModifiedTime = dbFile.lastModified()
|
||||
}
|
||||
} catch (e: JsonException) {
|
||||
logger.error("Cannot load JSON file!", e)
|
||||
} catch (e: IOException) {
|
||||
logger.error("Cannot load JSON file!", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun save() {
|
||||
if (readOnly) {
|
||||
// don't accidentally save this!
|
||||
return
|
||||
}
|
||||
|
||||
// if we cannot save, then we create a NEW properties file. It could have been DELETED out from under us (while in use!)
|
||||
if (!dbFile.canRead() && !dbFile.parentFile.mkdirs() && !dbFile.createNewFile()) {
|
||||
throw IOException("Cannot create file")
|
||||
}
|
||||
|
||||
try {
|
||||
synchronized(dbFile) {
|
||||
val data = json.toJson(loadedProps)
|
||||
val pretty = json.prettyPrint(data)
|
||||
dbFile.writeText(pretty)
|
||||
lastModifiedTime = dbFile.lastModified()
|
||||
}
|
||||
} catch (e: JsonException) {
|
||||
logger.error("JSON cannot save to: $dbFile", e)
|
||||
} catch (e: IOException) {
|
||||
logger.error("JSON cannot save to: $dbFile", e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setVersion(version: Long) {
|
||||
this.version = version
|
||||
}
|
||||
|
||||
override fun file(): File {
|
||||
return dbFile
|
||||
}
|
||||
|
||||
override fun size(): Int {
|
||||
return loadedProps.size
|
||||
}
|
||||
|
||||
override fun contains(key: Any): Boolean {
|
||||
require(key is String) {
|
||||
"Keys for a json file must be a String"
|
||||
}
|
||||
|
||||
if (autoLoad) {
|
||||
// we want to check the last modified time when getting, because if we edit the on-disk file, we want to load those changes
|
||||
val lastModifiedTime = dbFile.lastModified()
|
||||
if (this.lastModifiedTime != lastModifiedTime) {
|
||||
// we want to reload the info
|
||||
load()
|
||||
}
|
||||
}
|
||||
|
||||
return loadedProps[key] != null
|
||||
}
|
||||
|
||||
override operator fun <V> get(key: Any): V? {
|
||||
require(key is String) {
|
||||
"Keys for a json file must be a String"
|
||||
}
|
||||
|
||||
if (autoLoad) {
|
||||
// we want to check the last modified time when getting, because if we edit the on-disk file, we want to load those changes
|
||||
val lastModifiedTime = dbFile.lastModified()
|
||||
if (this.lastModifiedTime != lastModifiedTime) {
|
||||
// we want to reload the info
|
||||
load()
|
||||
}
|
||||
}
|
||||
|
||||
val any = loadedProps[key]
|
||||
if (any != null) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return any as V
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override operator fun set(key: Any, data: Any?) {
|
||||
require(key is String) {
|
||||
"Keys for a json file must be a String"
|
||||
}
|
||||
|
||||
if (readOnly) {
|
||||
if (readOnlyViolent) {
|
||||
throw IOException("Unable to save data in $dbFile for $key : $data")
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val hasChanged = if (data == null) {
|
||||
loadedProps.remove(key) != null
|
||||
} else {
|
||||
val prev = loadedProps.put(key, data)
|
||||
prev !== data
|
||||
}
|
||||
|
||||
// every time we set info, we want to save it to disk (so the file on disk will ALWAYS be current, and so we can modify it as we choose)
|
||||
if (hasChanged) {
|
||||
save()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all contents of this storage, and if applicable, it's location on disk.
|
||||
*/
|
||||
override fun deleteAll() {
|
||||
if (readOnly) {
|
||||
if (readOnlyViolent) {
|
||||
throw IOException("Unable to delete all data in $dbFile")
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
loadedProps.clear()
|
||||
dbFile.delete()
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this storage (and if applicable, flushes it's content to disk)
|
||||
*/
|
||||
override fun close() {
|
||||
Runtime.getRuntime().removeShutdownHook(thread)
|
||||
save()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,8 +2,14 @@ module dorkbox.storage {
|
|||
exports dorkbox.storage;
|
||||
exports dorkbox.storage.types;
|
||||
|
||||
requires transitive dorkbox.byteUtils;
|
||||
requires transitive dorkbox.json;
|
||||
requires transitive dorkbox.minlog;
|
||||
requires transitive dorkbox.objectpool;
|
||||
requires transitive dorkbox.serializers;
|
||||
requires transitive dorkbox.updates;
|
||||
|
||||
requires transitive com.esotericsoftware.kryo;
|
||||
requires transitive org.slf4j;
|
||||
requires transitive io.github.microutils.kotlinlogging;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2021 dorkbox, llc
|
||||
* Copyright 2023 dorkbox, llc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -227,18 +227,25 @@ class StorageTest {
|
|||
|
||||
// @Test
|
||||
// fun json() {
|
||||
// val tmp = tmp().newFile()
|
||||
//// val tmp = tmp().newFile()
|
||||
// val tmp = File("json.config")
|
||||
//
|
||||
// val logger = KotlinLogging.logger("test")
|
||||
//
|
||||
// val tester = Tester("key1", "value1")
|
||||
//
|
||||
// // lambda's do NOT evaluate equality. Only reference equality.
|
||||
// val serializer = SerializerBytes {
|
||||
// register(Tester::class.java, TesterSerializer())
|
||||
// }
|
||||
//
|
||||
// // note: we want to auto-close the storage after we write/read it
|
||||
// val storage = Storage.Json().file(tmp).register(Tester::class.java, TesterSerializer()).build()
|
||||
// val storage = Storage.Json().file(tmp).logger(logger).serializer(serializer).build()
|
||||
// storage.use {
|
||||
// it["key1"] = tester
|
||||
// }
|
||||
//
|
||||
//
|
||||
// val storage2 = Storage.Property().file(tmp).register(Tester::class.java, TesterSerializer()).build()
|
||||
// val storage2 = Storage.Json().file(tmp).logger(logger).serializer(serializer).build()
|
||||
//
|
||||
// val tes: Tester? = storage2.use {
|
||||
// it["key1"]
|
||||
|
|
Loading…
Reference in New Issue