-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added a way to persist properties' values, #3
- Loading branch information
Showing
8 changed files
with
558 additions
and
0 deletions.
There are no files selected for viewing
46 changes: 46 additions & 0 deletions
46
properties/src/main/kotlin/net/aquadc/properties/persistence/ByteArrayPropertiesMemento.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package net.aquadc.properties.persistence | ||
|
||
import java.io.* | ||
|
||
/** | ||
* Captures properties' value into a [ByteArray] eagerly. | ||
*/ | ||
class ByteArrayPropertiesMemento : PropertiesMemento, Externalizable { | ||
|
||
constructor(props: PersistableProperties) { | ||
val os = ByteArrayOutputStream() | ||
props.saveOrRestore(PropertyOutput(DataOutputStream(os))) | ||
bytes = os.toByteArray() | ||
} | ||
|
||
constructor() { | ||
bytes = EMPTY | ||
} | ||
|
||
private var bytes: ByteArray | ||
|
||
override fun writeExternal(out: ObjectOutput) { | ||
val bytes = bytes | ||
out.writeInt(bytes.size) | ||
out.write(bytes) | ||
} | ||
|
||
override fun readExternal(oi: ObjectInput) { | ||
val ba = ByteArray(oi.readInt()) | ||
oi.read(ba) | ||
bytes = ba | ||
} | ||
|
||
override fun restoreTo(target: PersistableProperties) { | ||
target.saveOrRestore(PropertyInput(DataInputStream(ByteArrayInputStream(bytes)))) | ||
} | ||
|
||
fun copyValue(): ByteArray = | ||
bytes.clone() | ||
|
||
companion object { | ||
private const val serialVersionUid: Long = 1 | ||
private val EMPTY = ByteArray(0) | ||
} | ||
|
||
} |
14 changes: 14 additions & 0 deletions
14
properties/src/main/kotlin/net/aquadc/properties/persistence/PersistableProperties.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package net.aquadc.properties.persistence | ||
|
||
/** | ||
* Describes a state-class which can be saved and restored. | ||
*/ | ||
interface PersistableProperties { | ||
|
||
/** | ||
* Gives properties to (de)serializer. | ||
* Should consist of [x] method calls. | ||
*/ | ||
fun saveOrRestore(d: PropertyIo) | ||
|
||
} |
13 changes: 13 additions & 0 deletions
13
properties/src/main/kotlin/net/aquadc/properties/persistence/PropertiesMemento.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package net.aquadc.properties.persistence | ||
|
||
/** | ||
* Describes an object which holds data from properties. | ||
*/ | ||
interface PropertiesMemento { | ||
|
||
/** | ||
* Pushes encapsulated data into [target]. | ||
*/ | ||
fun restoreTo(target: PersistableProperties) | ||
|
||
} |
70 changes: 70 additions & 0 deletions
70
properties/src/main/kotlin/net/aquadc/properties/persistence/PropertyBuffer.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package net.aquadc.properties.persistence | ||
|
||
import net.aquadc.properties.MutableProperty | ||
import java.lang.reflect.InvocationHandler | ||
import java.lang.reflect.Method | ||
import java.lang.reflect.Proxy | ||
import java.util.concurrent.atomic.AtomicReference | ||
|
||
/** | ||
* [InvocationHandler] for [PropertyIo]. | ||
* Reads properties' values into buffers; | ||
* writes buffered values into properties. | ||
*/ | ||
class PropertyBuffer private constructor() : InvocationHandler { | ||
|
||
private val values = ArrayList<Any?>() | ||
private var produceNext = -1 | ||
|
||
override fun invoke(proxy: Any?, method: Method, args: Array<out Any>): Any? { | ||
@Suppress("UNCHECKED_CAST") // won't explode if used properly | ||
val prop = args[0] as MutableProperty<Any?> | ||
if (produceNext == -1) { // consume | ||
values.add(prop.value) | ||
} else { // produce | ||
val idx = produceNext++ | ||
prop.value = values[idx] | ||
values[idx] = null | ||
} | ||
return null | ||
} | ||
|
||
fun produceThen() { | ||
check(produceNext == -1) | ||
produceNext = 0 | ||
} | ||
|
||
fun consumeThen() { | ||
check(produceNext == values.size) | ||
values.clear() | ||
produceNext = -1 | ||
} | ||
|
||
fun assertClean() { | ||
check(produceNext == -1) | ||
check(values.isEmpty()) | ||
} | ||
|
||
companion object { | ||
private val ref = AtomicReference<Pair<PropertyIo, PropertyBuffer>?>(null) | ||
fun get(): Pair<PropertyIo, PropertyBuffer> { | ||
ref.getAndSet(null)?.let { return it } | ||
val buf = PropertyBuffer() | ||
val proxy = Proxy.newProxyInstance(PropertyIo::class.java.classLoader, arrayOf(PropertyIo::class.java), buf) as PropertyIo | ||
return proxy to buf | ||
} | ||
fun recycle(buffer: Pair<PropertyIo, PropertyBuffer>) { | ||
check(Proxy.getInvocationHandler(buffer.first) === buffer.second) | ||
buffer.second.assertClean() | ||
ref.set(buffer) | ||
} | ||
inline fun <R> borrow(block: (PropertyIo, PropertyBuffer) -> R): R { | ||
val pdPb = get() | ||
val (pd, pb) = pdPb | ||
val ret = block(pd, pb) | ||
recycle(pdPb) | ||
return ret | ||
} | ||
} | ||
|
||
} |
82 changes: 82 additions & 0 deletions
82
properties/src/main/kotlin/net/aquadc/properties/persistence/PropertyInput.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package net.aquadc.properties.persistence | ||
|
||
import net.aquadc.properties.MutableProperty | ||
import java.io.DataInput | ||
import java.util.* | ||
|
||
/** | ||
* Reads data from [input] into properties. | ||
*/ | ||
class PropertyInput( | ||
private val input: DataInput | ||
) : PropertyIo { | ||
|
||
override fun bool(prop: MutableProperty<Boolean>) { | ||
prop.value = input.readBoolean() | ||
} | ||
override fun byte(prop: MutableProperty<Byte>) { | ||
prop.value = input.readByte() | ||
} | ||
override fun short(prop: MutableProperty<Short>) { | ||
prop.value = input.readShort() | ||
} | ||
override fun char(prop: MutableProperty<Char>) { | ||
prop.value = input.readChar() | ||
} | ||
override fun int(prop: MutableProperty<Int>) { | ||
prop.value = input.readInt() | ||
} | ||
override fun long(prop: MutableProperty<Long>) { | ||
prop.value = input.readLong() | ||
} | ||
override fun float(prop: MutableProperty<Float>) { | ||
prop.value = input.readFloat() | ||
} | ||
override fun double(prop: MutableProperty<Double>) { | ||
prop.value = input.readDouble() | ||
} | ||
|
||
override fun bytes(prop: MutableProperty<ByteArray>) { | ||
prop.value = ByteArray(input.readInt()).also(input::readFully) | ||
} | ||
override fun shorts(prop: MutableProperty<ShortArray>) { | ||
prop.value = ShortArray(input.readInt()) { input.readShort() } | ||
} | ||
override fun chars(prop: MutableProperty<CharArray>) { | ||
prop.value = CharArray(input.readInt()) { input.readChar() } | ||
} | ||
override fun ints(prop: MutableProperty<IntArray>) { | ||
prop.value = IntArray(input.readInt()) { input.readInt() } | ||
} | ||
override fun longs(prop: MutableProperty<LongArray>) { | ||
prop.value = LongArray(input.readInt()) { input.readLong() } | ||
} | ||
override fun floats(prop: MutableProperty<FloatArray>) { | ||
prop.value = FloatArray(input.readInt()) { input.readFloat() } | ||
} | ||
override fun doubles(prop: MutableProperty<DoubleArray>) { | ||
prop.value = DoubleArray(input.readInt()) { input.readDouble() } | ||
} | ||
|
||
override fun string(prop: MutableProperty<String>) { | ||
prop.value = input.readUTF() | ||
} | ||
override fun stringArr(prop: MutableProperty<Array<String>>) { | ||
prop.value = Array(input.readInt()) { input.readUTF() } | ||
} | ||
override fun stringList(prop: MutableProperty<List<String>>) { | ||
prop.value = List(input.readInt()) { input.readUTF() } | ||
} | ||
|
||
override fun <E : Enum<E>> enum(prop: MutableProperty<E>, type: Class<E>) { | ||
prop.value = java.lang.Enum.valueOf(type, input.readUTF()) | ||
} | ||
override fun <E : Enum<E>> enumSet(prop: MutableProperty<Set<E>>, type: Class<E>) { | ||
prop.value = EnumSet.noneOf(type).also { set -> | ||
repeat(input.readInt()) { | ||
set.add(java.lang.Enum.valueOf(type, input.readUTF())) | ||
} | ||
} | ||
} | ||
|
||
} |
62 changes: 62 additions & 0 deletions
62
properties/src/main/kotlin/net/aquadc/properties/persistence/PropertyIo.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package net.aquadc.properties.persistence | ||
|
||
import net.aquadc.properties.MutableProperty | ||
import java.util.* | ||
|
||
|
||
interface PropertyIo { | ||
fun bool(prop: MutableProperty<Boolean>) | ||
fun byte(prop: MutableProperty<Byte>) | ||
fun short(prop: MutableProperty<Short>) | ||
fun char(prop: MutableProperty<Char>) | ||
fun int(prop: MutableProperty<Int>) | ||
fun long(prop: MutableProperty<Long>) | ||
fun float(prop: MutableProperty<Float>) | ||
fun double(prop: MutableProperty<Double>) | ||
|
||
fun bytes(prop: MutableProperty<ByteArray>) | ||
fun shorts(prop: MutableProperty<ShortArray>) | ||
fun chars(prop: MutableProperty<CharArray>) | ||
fun ints(prop: MutableProperty<IntArray>) | ||
fun longs(prop: MutableProperty<LongArray>) | ||
fun floats(prop: MutableProperty<FloatArray>) | ||
fun doubles(prop: MutableProperty<DoubleArray>) | ||
|
||
fun string(prop: MutableProperty<String>) | ||
fun stringArr(prop: MutableProperty<Array<String>>) | ||
fun stringList(prop: MutableProperty<List<String>>) | ||
|
||
fun <E : Enum<E>> enum(prop: MutableProperty<E>, type: Class<E>) | ||
fun <E : Enum<E>> enumSet(prop: MutableProperty<Set<E>>, type: Class<E>) | ||
} | ||
|
||
|
||
@JvmName("bool") inline infix fun PropertyIo.x(prop: MutableProperty<Boolean>) = bool(prop) | ||
@JvmName("byte") inline infix fun PropertyIo.x(prop: MutableProperty<Byte>) = byte(prop) | ||
@JvmName("short") inline infix fun PropertyIo.x(prop: MutableProperty<Short>) = short(prop) | ||
@JvmName("char") inline infix fun PropertyIo.x(prop: MutableProperty<Char>) = char(prop) | ||
@JvmName("int") inline infix fun PropertyIo.x(prop: MutableProperty<Int>) = int(prop) | ||
@JvmName("long") inline infix fun PropertyIo.x(prop: MutableProperty<Long>) = long(prop) | ||
@JvmName("float") inline infix fun PropertyIo.x(prop: MutableProperty<Float>) = float(prop) | ||
@JvmName("double") inline infix fun PropertyIo.x(prop: MutableProperty<Double>) = double(prop) | ||
|
||
@JvmName("bytes") inline infix fun PropertyIo.x(prop: MutableProperty<ByteArray>) = bytes(prop) | ||
@JvmName("shorts") inline infix fun PropertyIo.x(prop: MutableProperty<ShortArray>) = shorts(prop) | ||
@JvmName("chars") inline infix fun PropertyIo.x(prop: MutableProperty<CharArray>) = chars(prop) | ||
@JvmName("ints") inline infix fun PropertyIo.x(prop: MutableProperty<IntArray>) = ints(prop) | ||
@JvmName("longs") inline infix fun PropertyIo.x(prop: MutableProperty<LongArray>) = longs(prop) | ||
@JvmName("floats") inline infix fun PropertyIo.x(prop: MutableProperty<FloatArray>) = floats(prop) | ||
@JvmName("doubles") inline infix fun PropertyIo.x(prop: MutableProperty<DoubleArray>) = doubles(prop) | ||
|
||
@JvmName("string") inline infix fun PropertyIo.x(prop: MutableProperty<String>) = string(prop) | ||
@JvmName("stringArr") inline infix fun PropertyIo.x(prop: MutableProperty<Array<String>>) = stringArr(prop) | ||
@JvmName("stringList") inline infix fun PropertyIo.x(prop: MutableProperty<List<String>>) = stringList(prop) | ||
|
||
@JvmName("enum") inline infix fun <reified E : Enum<E>> PropertyIo.x(prop: MutableProperty<E>) = | ||
enum(prop, E::class.java) | ||
@JvmName("enumSet") inline infix fun <reified E : Enum<E>> PropertyIo.x(prop: MutableProperty<Set<E>>) = | ||
enumSet(prop, E::class.java) | ||
|
||
@Suppress("UNCHECKED_CAST") // we'll read it as Set and write as EnumSet | ||
@JvmName("realEnumSet") inline infix fun <reified E : Enum<E>> PropertyIo.x(prop: MutableProperty<EnumSet<E>>) = | ||
enumSet(prop as MutableProperty<Set<E>>, E::class.java) |
97 changes: 97 additions & 0 deletions
97
properties/src/main/kotlin/net/aquadc/properties/persistence/PropertyOutput.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package net.aquadc.properties.persistence | ||
|
||
import net.aquadc.properties.MutableProperty | ||
import java.io.DataOutput | ||
|
||
/** | ||
* Writes data from properties into [output]. | ||
*/ | ||
class PropertyOutput( | ||
private val output: DataOutput | ||
) : PropertyIo { | ||
|
||
override fun bool(prop: MutableProperty<Boolean>) { | ||
output.writeBoolean(prop.value) | ||
} | ||
override fun byte(prop: MutableProperty<Byte>) { | ||
output.writeByte(prop.value.toInt()) | ||
} | ||
override fun short(prop: MutableProperty<Short>) { | ||
output.writeShort(prop.value.toInt()) | ||
} | ||
override fun char(prop: MutableProperty<Char>) { | ||
output.writeChar(prop.value.toInt()) | ||
} | ||
override fun int(prop: MutableProperty<Int>) { | ||
output.writeInt(prop.value) | ||
} | ||
override fun long(prop: MutableProperty<Long>) { | ||
output.writeLong(prop.value) | ||
} | ||
override fun float(prop: MutableProperty<Float>) { | ||
output.writeFloat(prop.value) | ||
} | ||
override fun double(prop: MutableProperty<Double>) { | ||
output.writeDouble(prop.value) | ||
} | ||
|
||
override fun bytes(prop: MutableProperty<ByteArray>) { | ||
val value = prop.value | ||
output.writeInt(value.size) | ||
output.write(value) | ||
} | ||
override fun shorts(prop: MutableProperty<ShortArray>) { | ||
val value = prop.value | ||
output.writeInt(value.size) | ||
value.forEach { output.writeShort(it.toInt()) } | ||
} | ||
override fun chars(prop: MutableProperty<CharArray>) { | ||
val value = prop.value | ||
output.writeInt(value.size) | ||
value.forEach { output.writeChar(it.toInt()) } | ||
} | ||
override fun ints(prop: MutableProperty<IntArray>) { | ||
val value = prop.value | ||
output.writeInt(value.size) | ||
value.forEach(output::writeInt) | ||
} | ||
override fun longs(prop: MutableProperty<LongArray>) { | ||
val value = prop.value | ||
output.writeInt(value.size) | ||
value.forEach(output::writeLong) | ||
} | ||
override fun floats(prop: MutableProperty<FloatArray>) { | ||
val value = prop.value | ||
output.writeInt(value.size) | ||
value.forEach(output::writeFloat) | ||
} | ||
override fun doubles(prop: MutableProperty<DoubleArray>) { | ||
val value = prop.value | ||
output.writeInt(value.size) | ||
value.forEach(output::writeDouble) | ||
} | ||
|
||
override fun string(prop: MutableProperty<String>) { | ||
output.writeUTF(prop.value) | ||
} | ||
override fun stringArr(prop: MutableProperty<Array<String>>) { | ||
val value = prop.value | ||
output.writeInt(value.size) | ||
value.forEach(output::writeUTF) | ||
} | ||
override fun stringList(prop: MutableProperty<List<String>>) { | ||
val value = prop.value | ||
output.writeInt(value.size) | ||
for (i in 0 until value.size) output.writeUTF(value[i]) | ||
} | ||
|
||
override fun <E : Enum<E>> enum(prop: MutableProperty<E>, type: Class<E>) { | ||
output.writeUTF(prop.value.name) | ||
} | ||
override fun <E : Enum<E>> enumSet(prop: MutableProperty<Set<E>>, type: Class<E>) { | ||
val value = prop.value | ||
output.writeInt(value.size) | ||
value.forEach { output.writeUTF(it.name) } | ||
} | ||
|
||
} |
Oops, something went wrong.