mirror of
https://github.com/corda/corda.git
synced 2025-01-22 20:38:05 +00:00
CORDA-716 Rename one TestClock to DemoClock, and unduplicate code (#1988)
This commit is contained in:
parent
9baa9037ae
commit
00a9014852
61
node/src/main/kotlin/net/corda/node/internal/CordaClock.kt
Normal file
61
node/src/main/kotlin/net/corda/node/internal/CordaClock.kt
Normal file
@ -0,0 +1,61 @@
|
||||
package net.corda.node.internal
|
||||
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.SerializeAsTokenContext
|
||||
import net.corda.core.serialization.SingletonSerializationToken
|
||||
import rx.Observable
|
||||
import rx.Subscriber
|
||||
import rx.subscriptions.Subscriptions
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.time.ZoneId
|
||||
import java.util.concurrent.CopyOnWriteArraySet
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
|
||||
/** A [Clock] that tokenizes itself when serialized, and delegates to an underlying [Clock] implementation. */
|
||||
abstract class CordaClock : Clock(), SerializeAsToken {
|
||||
protected abstract val delegateClock: Clock
|
||||
private val token = SingletonSerializationToken.singletonSerializationToken(javaClass)
|
||||
override fun toToken(context: SerializeAsTokenContext) = token.registerWithContext(context, this)
|
||||
override fun instant(): Instant = delegateClock.instant()
|
||||
override fun getZone(): ZoneId = delegateClock.zone
|
||||
@Deprecated("Do not use this. Instead seek to use ZonedDateTime methods.", level = DeprecationLevel.ERROR)
|
||||
override fun withZone(zone: ZoneId) = throw UnsupportedOperationException("Tokenized clock does not support withZone()")
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
class SimpleClock(override val delegateClock: Clock) : CordaClock()
|
||||
|
||||
/**
|
||||
* An abstract class with helper methods for a type of Clock that might have it's concept of "now" adjusted externally.
|
||||
* e.g. for testing (so unit tests do not have to wait for timeouts in realtime) or for demos and simulations.
|
||||
*/
|
||||
abstract class MutableClock(private var _delegateClock: Clock) : CordaClock() {
|
||||
override var delegateClock
|
||||
@Synchronized get() = _delegateClock
|
||||
@Synchronized set(clock) {
|
||||
_delegateClock = clock
|
||||
}
|
||||
private val _version = AtomicLong(0L)
|
||||
/** This is an observer on the mutation count of this [Clock], which reflects the occurence of mutations. */
|
||||
val mutations: Observable<Long> by lazy {
|
||||
Observable.create { subscriber: Subscriber<in Long> ->
|
||||
if (!subscriber.isUnsubscribed) {
|
||||
mutationObservers.add(subscriber)
|
||||
// This is not very intuitive, but subscribing to a subscriber observes unsubscribes.
|
||||
subscriber.add(Subscriptions.create { mutationObservers.remove(subscriber) })
|
||||
}
|
||||
}
|
||||
}
|
||||
private val mutationObservers = CopyOnWriteArraySet<Subscriber<in Long>>()
|
||||
/** Must be called by subclasses when they mutate (but not just with the passage of time as per the "wall clock"). */
|
||||
protected fun notifyMutationObservers() {
|
||||
val version = _version.incrementAndGet()
|
||||
for (observer in mutationObservers) {
|
||||
if (!observer.isUnsubscribed) {
|
||||
observer.onNext(version)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package net.corda.node.internal
|
||||
|
||||
import rx.Observable
|
||||
import rx.Subscriber
|
||||
import rx.subscriptions.Subscriptions
|
||||
import java.time.Clock
|
||||
import java.util.concurrent.CopyOnWriteArraySet
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
/**
|
||||
* An abstract class with helper methods for a type of Clock that might have it's concept of "now"
|
||||
* adjusted externally.
|
||||
*
|
||||
* e.g. for testing (so unit tests do not have to wait for timeouts in realtime) or for demos and simulations.
|
||||
*/
|
||||
abstract class MutableClock : Clock() {
|
||||
private val _version = AtomicLong(0L)
|
||||
|
||||
/**
|
||||
* This is an observer on the mutation count of this [Clock], which reflects the occurence of mutations.
|
||||
*/
|
||||
val mutations: Observable<Long> by lazy {
|
||||
Observable.create({ subscriber: Subscriber<in Long> ->
|
||||
if (!subscriber.isUnsubscribed) {
|
||||
mutationObservers.add(subscriber)
|
||||
// This is not very intuitive, but subscribing to a subscriber observes unsubscribes.
|
||||
subscriber.add(Subscriptions.create { mutationObservers.remove(subscriber) })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private val mutationObservers = CopyOnWriteArraySet<Subscriber<in Long>>()
|
||||
|
||||
/**
|
||||
* Must be called by subclasses when they mutate (but not just with the passage of time as per the "wall clock").
|
||||
*/
|
||||
protected fun notifyMutationObservers() {
|
||||
val version = _version.incrementAndGet()
|
||||
for (observer in mutationObservers) {
|
||||
if (!observer.isUnsubscribed) {
|
||||
observer.onNext(version)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -15,7 +15,6 @@ import net.corda.core.utilities.loggerFor
|
||||
import net.corda.node.VersionInfo
|
||||
import net.corda.node.internal.cordapp.CordappLoader
|
||||
import net.corda.node.serialization.KryoServerSerializationScheme
|
||||
import net.corda.node.serialization.NodeClock
|
||||
import net.corda.node.services.RPCUserService
|
||||
import net.corda.node.services.RPCUserServiceImpl
|
||||
import net.corda.node.services.api.SchemaService
|
||||
@ -25,7 +24,7 @@ import net.corda.node.services.messaging.MessagingService
|
||||
import net.corda.node.services.messaging.NodeMessagingClient
|
||||
import net.corda.node.utilities.AddressUtils
|
||||
import net.corda.node.utilities.AffinityExecutor
|
||||
import net.corda.node.utilities.TestClock
|
||||
import net.corda.node.utilities.DemoClock
|
||||
import net.corda.nodeapi.ArtemisMessagingComponent
|
||||
import net.corda.nodeapi.internal.ShutdownHook
|
||||
import net.corda.nodeapi.internal.addShutdownHook
|
||||
@ -67,7 +66,7 @@ open class Node(configuration: NodeConfiguration,
|
||||
}
|
||||
|
||||
private fun createClock(configuration: NodeConfiguration): Clock {
|
||||
return if (configuration.useTestClock) TestClock() else NodeClock()
|
||||
return (if (configuration.useTestClock) ::DemoClock else ::SimpleClock)(Clock.systemUTC())
|
||||
}
|
||||
|
||||
private val sameVmNodeCounter = AtomicInteger()
|
||||
|
@ -1,36 +0,0 @@
|
||||
package net.corda.node.serialization
|
||||
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.SerializeAsTokenContext
|
||||
import net.corda.core.serialization.SingletonSerializationToken
|
||||
import net.corda.core.serialization.SingletonSerializationToken.Companion.singletonSerializationToken
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.time.ZoneId
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
|
||||
|
||||
/**
|
||||
* A [Clock] that tokenizes itself when serialized, and delegates to an underlying [Clock] implementation.
|
||||
*/
|
||||
@ThreadSafe
|
||||
class NodeClock(private val delegateClock: Clock = Clock.systemUTC()) : Clock(), SerializeAsToken {
|
||||
|
||||
private val token = singletonSerializationToken(javaClass)
|
||||
|
||||
override fun toToken(context: SerializeAsTokenContext) = token.registerWithContext(context, this)
|
||||
|
||||
override fun instant(): Instant {
|
||||
return delegateClock.instant()
|
||||
}
|
||||
|
||||
// Do not use this. Instead seek to use ZonedDateTime methods.
|
||||
override fun withZone(zone: ZoneId): Clock {
|
||||
throw UnsupportedOperationException("Tokenized clock does not support withZone()")
|
||||
}
|
||||
|
||||
override fun getZone(): ZoneId {
|
||||
return delegateClock.zone
|
||||
}
|
||||
|
||||
}
|
23
node/src/main/kotlin/net/corda/node/utilities/DemoClock.kt
Normal file
23
node/src/main/kotlin/net/corda/node/utilities/DemoClock.kt
Normal file
@ -0,0 +1,23 @@
|
||||
package net.corda.node.utilities
|
||||
|
||||
import net.corda.core.internal.until
|
||||
import net.corda.node.internal.MutableClock
|
||||
import java.time.Clock
|
||||
import java.time.LocalDate
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
|
||||
/** A [Clock] that can have the date advanced for use in demos. */
|
||||
@ThreadSafe
|
||||
class DemoClock(delegateClock: Clock) : MutableClock(delegateClock) {
|
||||
@Synchronized
|
||||
fun updateDate(date: LocalDate): Boolean {
|
||||
val currentDate = LocalDate.now(this)
|
||||
if (currentDate.isBefore(date)) {
|
||||
// It's ok to increment
|
||||
delegateClock = Clock.offset(delegateClock, currentDate.atStartOfDay() until date.atStartOfDay())
|
||||
notifyMutationObservers()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package net.corda.node.utilities
|
||||
|
||||
import net.corda.core.internal.until
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.SerializeAsTokenContext
|
||||
import net.corda.core.serialization.SingletonSerializationToken.Companion.singletonSerializationToken
|
||||
import net.corda.node.internal.MutableClock
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.ZoneId
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
|
||||
/**
|
||||
* A [Clock] that can have the date advanced for use in demos.
|
||||
*/
|
||||
@ThreadSafe
|
||||
class TestClock(private var delegateClock: Clock = Clock.systemUTC()) : MutableClock(), SerializeAsToken {
|
||||
|
||||
private val token = singletonSerializationToken(javaClass)
|
||||
|
||||
override fun toToken(context: SerializeAsTokenContext) = token.registerWithContext(context, this)
|
||||
|
||||
@Synchronized
|
||||
fun updateDate(date: LocalDate): Boolean {
|
||||
val currentDate = LocalDate.now(this)
|
||||
if (currentDate.isBefore(date)) {
|
||||
// It's ok to increment
|
||||
delegateClock = Clock.offset(delegateClock, currentDate.atStartOfDay() until date.atStartOfDay())
|
||||
notifyMutationObservers()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@Synchronized override fun instant(): Instant {
|
||||
return delegateClock.instant()
|
||||
}
|
||||
|
||||
// Do not use this. Instead seek to use ZonedDateTime methods.
|
||||
override fun withZone(zone: ZoneId): Clock {
|
||||
throw UnsupportedOperationException("Tokenized clock does not support withZone()")
|
||||
}
|
||||
|
||||
@Synchronized override fun getZone(): ZoneId {
|
||||
return delegateClock.zone
|
||||
}
|
||||
|
||||
}
|
@ -7,11 +7,10 @@ import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.core.utilities.unwrap
|
||||
import net.corda.node.utilities.TestClock
|
||||
import net.corda.node.utilities.DemoClock
|
||||
import java.time.LocalDate
|
||||
|
||||
/**
|
||||
@ -27,7 +26,7 @@ object UpdateBusinessDayFlow {
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
val message = otherPartySession.receive<UpdateBusinessDayMessage>().unwrap { it }
|
||||
(serviceHub.clock as TestClock).updateDate(message.date)
|
||||
(serviceHub.clock as DemoClock).updateDate(message.date)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,8 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
||||
init {
|
||||
// Advance node clocks when current time is changed
|
||||
dateChanges.subscribe {
|
||||
clocks.setTo(currentDateAndTime.toInstant(ZoneOffset.UTC))
|
||||
val instant = currentDateAndTime.toInstant(ZoneOffset.UTC)
|
||||
clocks.forEach { it.setTo(instant) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ import java.math.BigInteger
|
||||
import java.nio.file.Path
|
||||
import java.security.KeyPair
|
||||
import java.security.PublicKey
|
||||
import java.time.Clock
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
@ -217,7 +218,7 @@ class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParamete
|
||||
|
||||
open class MockNode(args: MockNodeArgs) : AbstractNode(
|
||||
args.config,
|
||||
TestClock(),
|
||||
TestClock(Clock.systemUTC()),
|
||||
MOCK_VERSION_INFO,
|
||||
CordappLoader.createDefaultWithTestPackages(args.config, args.network.cordappPackages),
|
||||
args.network.busyLatch
|
||||
|
@ -1,30 +1,16 @@
|
||||
package net.corda.testing.node
|
||||
|
||||
import net.corda.core.internal.until
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.SerializeAsTokenContext
|
||||
import net.corda.core.serialization.SingletonSerializationToken.Companion.singletonSerializationToken
|
||||
import net.corda.node.internal.MutableClock
|
||||
import java.time.Clock
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.time.ZoneId
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
|
||||
|
||||
/**
|
||||
* A [Clock] that can have the time advanced for use in testing.
|
||||
*/
|
||||
/** A [Clock] that can have the time advanced for use in testing. */
|
||||
@ThreadSafe
|
||||
class TestClock(private var delegateClock: Clock = Clock.systemUTC()) : MutableClock(), SerializeAsToken {
|
||||
|
||||
private val token = singletonSerializationToken(javaClass)
|
||||
|
||||
override fun toToken(context: SerializeAsTokenContext) = token.registerWithContext(context, this)
|
||||
|
||||
/**
|
||||
* Advance this [Clock] by the specified [Duration] for testing purposes.
|
||||
*/
|
||||
class TestClock(delegateClock: Clock) : MutableClock(delegateClock) {
|
||||
/** Advance this [Clock] by the specified [Duration] for testing purposes. */
|
||||
@Synchronized
|
||||
fun advanceBy(duration: Duration) {
|
||||
delegateClock = offset(delegateClock, duration)
|
||||
@ -33,28 +19,8 @@ class TestClock(private var delegateClock: Clock = Clock.systemUTC()) : MutableC
|
||||
|
||||
/**
|
||||
* Move this [Clock] to the specified [Instant] for testing purposes.
|
||||
*
|
||||
* This will only be approximate due to the time ticking away, but will be some time shortly after the requested [Instant].
|
||||
*/
|
||||
@Synchronized
|
||||
fun setTo(newInstant: Instant) = advanceBy(instant() until newInstant)
|
||||
|
||||
@Synchronized override fun instant(): Instant {
|
||||
return delegateClock.instant()
|
||||
}
|
||||
|
||||
@Deprecated("Do not use this. Instead seek to use ZonedDateTime methods.", level = DeprecationLevel.ERROR)
|
||||
override fun withZone(zone: ZoneId): Clock {
|
||||
throw UnsupportedOperationException("Tokenized clock does not support withZone()")
|
||||
}
|
||||
|
||||
@Synchronized override fun getZone(): ZoneId {
|
||||
return delegateClock.zone
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to set several [TestClock]s to approximately the same time. The clocks may drift by the time it
|
||||
* takes for each [TestClock] to have it's time set and any observers to execute.
|
||||
*/
|
||||
fun Iterable<TestClock>.setTo(instant: Instant) = this.forEach { it.setTo(instant) }
|
||||
|
Loading…
Reference in New Issue
Block a user