mirror of
https://github.com/corda/corda.git
synced 2025-06-01 15:10:54 +00:00
commit
dea7d0b905
@ -5,6 +5,10 @@ package net.corda.core.node.services.vault
|
|||||||
import net.corda.core.DoNotImplement
|
import net.corda.core.DoNotImplement
|
||||||
import net.corda.core.internal.declaredField
|
import net.corda.core.internal.declaredField
|
||||||
import net.corda.core.internal.uncheckedCast
|
import net.corda.core.internal.uncheckedCast
|
||||||
|
import net.corda.core.node.services.vault.CollectionOperator.*
|
||||||
|
import net.corda.core.node.services.vault.ColumnPredicate.*
|
||||||
|
import net.corda.core.node.services.vault.EqualityComparisonOperator.*
|
||||||
|
import net.corda.core.node.services.vault.LikenessOperator.*
|
||||||
import net.corda.core.schemas.PersistentState
|
import net.corda.core.schemas.PersistentState
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
@ -24,7 +28,9 @@ enum class BinaryLogicalOperator : Operator {
|
|||||||
|
|
||||||
enum class EqualityComparisonOperator : Operator {
|
enum class EqualityComparisonOperator : Operator {
|
||||||
EQUAL,
|
EQUAL,
|
||||||
NOT_EQUAL
|
NOT_EQUAL,
|
||||||
|
EQUAL_IGNORE_CASE,
|
||||||
|
NOT_EQUAL_IGNORE_CASE
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class BinaryComparisonOperator : Operator {
|
enum class BinaryComparisonOperator : Operator {
|
||||||
@ -41,12 +47,16 @@ enum class NullOperator : Operator {
|
|||||||
|
|
||||||
enum class LikenessOperator : Operator {
|
enum class LikenessOperator : Operator {
|
||||||
LIKE,
|
LIKE,
|
||||||
NOT_LIKE
|
NOT_LIKE,
|
||||||
|
LIKE_IGNORE_CASE,
|
||||||
|
NOT_LIKE_IGNORE_CASE
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class CollectionOperator : Operator {
|
enum class CollectionOperator : Operator {
|
||||||
IN,
|
IN,
|
||||||
NOT_IN
|
NOT_IN,
|
||||||
|
IN_IGNORE_CASE,
|
||||||
|
NOT_IN_IGNORE_CASE
|
||||||
}
|
}
|
||||||
|
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
@ -251,27 +261,45 @@ object Builder {
|
|||||||
fun <R : Comparable<R>> Field.comparePredicate(operator: BinaryComparisonOperator, value: R) = info().comparePredicate(operator, value)
|
fun <R : Comparable<R>> Field.comparePredicate(operator: BinaryComparisonOperator, value: R) = info().comparePredicate(operator, value)
|
||||||
fun <R : Comparable<R>> FieldInfo.comparePredicate(operator: BinaryComparisonOperator, value: R) = predicate(compare(operator, value))
|
fun <R : Comparable<R>> FieldInfo.comparePredicate(operator: BinaryComparisonOperator, value: R) = predicate(compare(operator, value))
|
||||||
|
|
||||||
fun <O, R> KProperty1<O, R?>.equal(value: R) = predicate(ColumnPredicate.EqualityComparison(EqualityComparisonOperator.EQUAL, value))
|
@JvmOverloads
|
||||||
fun <O, R> KProperty1<O, R?>.notEqual(value: R) = predicate(ColumnPredicate.EqualityComparison(EqualityComparisonOperator.NOT_EQUAL, value))
|
fun <O, R> KProperty1<O, R?>.equal(value: R, exactMatch: Boolean = true) = predicate(Builder.equal(value, exactMatch))
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun <O, R> KProperty1<O, R?>.notEqual(value: R, exactMatch: Boolean = true) = predicate(Builder.notEqual(value, exactMatch))
|
||||||
|
|
||||||
fun <O, R : Comparable<R>> KProperty1<O, R?>.lessThan(value: R) = comparePredicate(BinaryComparisonOperator.LESS_THAN, value)
|
fun <O, R : Comparable<R>> KProperty1<O, R?>.lessThan(value: R) = comparePredicate(BinaryComparisonOperator.LESS_THAN, value)
|
||||||
|
|
||||||
fun <O, R : Comparable<R>> KProperty1<O, R?>.lessThanOrEqual(value: R) = comparePredicate(BinaryComparisonOperator.LESS_THAN_OR_EQUAL, value)
|
fun <O, R : Comparable<R>> KProperty1<O, R?>.lessThanOrEqual(value: R) = comparePredicate(BinaryComparisonOperator.LESS_THAN_OR_EQUAL, value)
|
||||||
|
|
||||||
fun <O, R : Comparable<R>> KProperty1<O, R?>.greaterThan(value: R) = comparePredicate(BinaryComparisonOperator.GREATER_THAN, value)
|
fun <O, R : Comparable<R>> KProperty1<O, R?>.greaterThan(value: R) = comparePredicate(BinaryComparisonOperator.GREATER_THAN, value)
|
||||||
|
|
||||||
fun <O, R : Comparable<R>> KProperty1<O, R?>.greaterThanOrEqual(value: R) = comparePredicate(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL, value)
|
fun <O, R : Comparable<R>> KProperty1<O, R?>.greaterThanOrEqual(value: R) = comparePredicate(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL, value)
|
||||||
|
|
||||||
fun <O, R : Comparable<R>> KProperty1<O, R?>.between(from: R, to: R) = predicate(ColumnPredicate.Between(from, to))
|
fun <O, R : Comparable<R>> KProperty1<O, R?>.between(from: R, to: R) = predicate(ColumnPredicate.Between(from, to))
|
||||||
fun <O, R : Comparable<R>> KProperty1<O, R?>.`in`(collection: Collection<R>) = predicate(ColumnPredicate.CollectionExpression(CollectionOperator.IN, collection))
|
|
||||||
fun <O, R : Comparable<R>> KProperty1<O, R?>.notIn(collection: Collection<R>) = predicate(ColumnPredicate.CollectionExpression(CollectionOperator.NOT_IN, collection))
|
@JvmOverloads
|
||||||
|
fun <O, R : Comparable<R>> KProperty1<O, R?>.`in`(collection: Collection<R>, exactMatch: Boolean = true) = predicate(Builder.`in`(collection, exactMatch))
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun <O, R : Comparable<R>> KProperty1<O, R?>.notIn(collection: Collection<R>, exactMatch: Boolean = true) = predicate(Builder.notIn(collection, exactMatch))
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
||||||
fun <R> Field.equal(value: R) = info().equal(value)
|
fun <R> Field.equal(value: R, exactMatch: Boolean = true) = info().equal(value, exactMatch)
|
||||||
@JvmStatic
|
|
||||||
fun <R> FieldInfo.equal(value: R) = predicate(ColumnPredicate.EqualityComparison(EqualityComparisonOperator.EQUAL, value))
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
@JvmOverloads
|
||||||
fun <R> Field.notEqual(value: R) = info().notEqual(value)
|
fun <R> FieldInfo.equal(value: R, exactMatch: Boolean = true) = predicate(Builder.equal(value, exactMatch))
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun <R> FieldInfo.notEqual(value: R) = predicate(ColumnPredicate.EqualityComparison(EqualityComparisonOperator.NOT_EQUAL, value))
|
@JvmOverloads
|
||||||
|
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
||||||
|
fun <R> Field.notEqual(value: R, exactMatch: Boolean = true) = info().notEqual(value, exactMatch)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun <R> FieldInfo.notEqual(value: R, exactMatch: Boolean = true) = predicate(Builder.equal(value, exactMatch))
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
||||||
@ -304,44 +332,77 @@ object Builder {
|
|||||||
fun <R : Comparable<R>> FieldInfo.between(from: R, to: R) = predicate(ColumnPredicate.Between(from, to))
|
fun <R : Comparable<R>> FieldInfo.between(from: R, to: R) = predicate(ColumnPredicate.Between(from, to))
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
||||||
fun <R : Comparable<R>> Field.`in`(collection: Collection<R>) = info().`in`(collection)
|
fun <R : Comparable<R>> Field.`in`(collection: Collection<R>, exactMatch: Boolean = true) = info().`in`(collection, exactMatch)
|
||||||
fun <R : Comparable<R>> FieldInfo.`in`(collection: Collection<R>) = predicate(ColumnPredicate.CollectionExpression(CollectionOperator.IN, collection))
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
@JvmOverloads
|
||||||
fun <R : Comparable<R>> Field.notIn(collection: Collection<R>) = info().notIn(collection)
|
fun <R : Comparable<R>> FieldInfo.`in`(collection: Collection<R>, exactMatch: Boolean = true) = predicate(Builder.`in`(collection, exactMatch))
|
||||||
@JvmStatic
|
|
||||||
fun <R : Comparable<R>> FieldInfo.notIn(collection: Collection<R>) = predicate(ColumnPredicate.CollectionExpression(CollectionOperator.NOT_IN, collection))
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
||||||
|
fun <R : Comparable<R>> Field.notIn(collection: Collection<R>, exactMatch: Boolean = true) = info().notIn(collection, exactMatch)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun <R : Comparable<R>> FieldInfo.notIn(collection: Collection<R>, exactMatch: Boolean = true) = predicate(Builder.notIn(collection, exactMatch))
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun <R> equal(value: R, exactMatch: Boolean = true) = EqualityComparison(if (exactMatch) EQUAL else EQUAL_IGNORE_CASE, value)
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun <R> notEqual(value: R, exactMatch: Boolean = true) = EqualityComparison(if (exactMatch) NOT_EQUAL else NOT_EQUAL_IGNORE_CASE, value)
|
||||||
|
|
||||||
fun <R> equal(value: R) = ColumnPredicate.EqualityComparison(EqualityComparisonOperator.EQUAL, value)
|
|
||||||
fun <R> notEqual(value: R) = ColumnPredicate.EqualityComparison(EqualityComparisonOperator.NOT_EQUAL, value)
|
|
||||||
fun <R : Comparable<R>> lessThan(value: R) = compare(BinaryComparisonOperator.LESS_THAN, value)
|
fun <R : Comparable<R>> lessThan(value: R) = compare(BinaryComparisonOperator.LESS_THAN, value)
|
||||||
|
|
||||||
fun <R : Comparable<R>> lessThanOrEqual(value: R) = compare(BinaryComparisonOperator.LESS_THAN_OR_EQUAL, value)
|
fun <R : Comparable<R>> lessThanOrEqual(value: R) = compare(BinaryComparisonOperator.LESS_THAN_OR_EQUAL, value)
|
||||||
|
|
||||||
fun <R : Comparable<R>> greaterThan(value: R) = compare(BinaryComparisonOperator.GREATER_THAN, value)
|
fun <R : Comparable<R>> greaterThan(value: R) = compare(BinaryComparisonOperator.GREATER_THAN, value)
|
||||||
|
|
||||||
fun <R : Comparable<R>> greaterThanOrEqual(value: R) = compare(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL, value)
|
fun <R : Comparable<R>> greaterThanOrEqual(value: R) = compare(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL, value)
|
||||||
|
|
||||||
fun <R : Comparable<R>> between(from: R, to: R) = ColumnPredicate.Between(from, to)
|
fun <R : Comparable<R>> between(from: R, to: R) = ColumnPredicate.Between(from, to)
|
||||||
fun <R : Comparable<R>> `in`(collection: Collection<R>) = ColumnPredicate.CollectionExpression(CollectionOperator.IN, collection)
|
|
||||||
fun <R : Comparable<R>> notIn(collection: Collection<R>) = ColumnPredicate.CollectionExpression(CollectionOperator.NOT_IN, collection)
|
@JvmOverloads
|
||||||
fun like(string: String) = ColumnPredicate.Likeness(LikenessOperator.LIKE, string)
|
fun <R : Comparable<R>> `in`(collection: Collection<R>, exactMatch: Boolean = true) = CollectionExpression(if (exactMatch) IN else IN_IGNORE_CASE, collection)
|
||||||
fun notLike(string: String) = ColumnPredicate.Likeness(LikenessOperator.NOT_LIKE, string)
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun <R : Comparable<R>> notIn(collection: Collection<R>, exactMatch: Boolean = true) = CollectionExpression(if (exactMatch) NOT_IN else NOT_IN_IGNORE_CASE, collection)
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun like(string: String, exactMatch: Boolean = true) = Likeness(if (exactMatch) LIKE else LIKE_IGNORE_CASE, string)
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun notLike(string: String, exactMatch: Boolean = true) = Likeness(if (exactMatch) NOT_LIKE else NOT_LIKE_IGNORE_CASE, string)
|
||||||
|
|
||||||
fun <R> isNull() = ColumnPredicate.NullExpression<R>(NullOperator.IS_NULL)
|
fun <R> isNull() = ColumnPredicate.NullExpression<R>(NullOperator.IS_NULL)
|
||||||
fun <R> isNotNull() = ColumnPredicate.NullExpression<R>(NullOperator.NOT_NULL)
|
fun <R> isNotNull() = ColumnPredicate.NullExpression<R>(NullOperator.NOT_NULL)
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun <O> KProperty1<O, String?>.like(string: String, exactMatch: Boolean = true) = predicate(Builder.like(string, exactMatch))
|
||||||
|
|
||||||
fun <O> KProperty1<O, String?>.like(string: String) = predicate(ColumnPredicate.Likeness(LikenessOperator.LIKE, string))
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
||||||
fun Field.like(string: String) = info().like(string)
|
fun Field.like(string: String, exactMatch: Boolean = true) = info().like(string, exactMatch)
|
||||||
@JvmStatic
|
|
||||||
fun FieldInfo.like(string: String) = predicate(ColumnPredicate.Likeness(LikenessOperator.LIKE, string))
|
|
||||||
|
|
||||||
fun <O> KProperty1<O, String?>.notLike(string: String) = predicate(ColumnPredicate.Likeness(LikenessOperator.NOT_LIKE, string))
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun FieldInfo.like(string: String, exactMatch: Boolean = true) = predicate(Builder.like(string, exactMatch))
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun <O> KProperty1<O, String?>.notLike(string: String, exactMatch: Boolean = true) = predicate(Builder.notLike(string, exactMatch))
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
||||||
fun Field.notLike(string: String) = info().notLike(string)
|
fun Field.notLike(string: String, exactMatch: Boolean = true) = info().notLike(string, exactMatch)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun FieldInfo.notLike(string: String) = predicate(ColumnPredicate.Likeness(LikenessOperator.NOT_LIKE, string))
|
@JvmOverloads
|
||||||
|
fun FieldInfo.notLike(string: String, exactMatch: Boolean = true) = predicate(Builder.notLike(string, exactMatch))
|
||||||
|
|
||||||
fun <O, R> KProperty1<O, R?>.isNull() = predicate(ColumnPredicate.NullExpression(NullOperator.IS_NULL))
|
fun <O, R> KProperty1<O, R?>.isNull() = predicate(ColumnPredicate.NullExpression(NullOperator.IS_NULL))
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@ -166,6 +166,44 @@ An example of a custom query in Java is illustrated here:
|
|||||||
where an anonymous party does not resolve to an X500 name via the ``IdentityService``, no query results will ever be
|
where an anonymous party does not resolve to an X500 name via the ``IdentityService``, no query results will ever be
|
||||||
produced. For performance reasons, queries do not use ``PublicKey`` as search criteria.
|
produced. For performance reasons, queries do not use ``PublicKey`` as search criteria.
|
||||||
|
|
||||||
|
Custom queries can be either case sensitive or case insensitive. They are defined via a ``Boolean`` as one of the function parameters of each operator function. By default each operator is case sensitive.
|
||||||
|
|
||||||
|
An example of a case sensitive custom query operator is illustrated here:
|
||||||
|
|
||||||
|
.. container:: codeset
|
||||||
|
|
||||||
|
.. sourcecode:: kotlin
|
||||||
|
|
||||||
|
val currencyIndex = PersistentCashState::currency.equal(USD.currencyCode, true)
|
||||||
|
|
||||||
|
.. note:: The ``Boolean`` input of ``true`` in this example could be removed since the function will default to ``true`` when not provided.
|
||||||
|
|
||||||
|
An example of a case insensitive custom query operator is illustrated here:
|
||||||
|
|
||||||
|
.. container:: codeset
|
||||||
|
|
||||||
|
.. sourcecode:: kotlin
|
||||||
|
|
||||||
|
val currencyIndex = PersistentCashState::currency.equal(USD.currencyCode, false)
|
||||||
|
|
||||||
|
An example of a case sensitive custom query operator in Java is illustrated here:
|
||||||
|
|
||||||
|
.. container:: codeset
|
||||||
|
|
||||||
|
.. sourcecode:: java
|
||||||
|
|
||||||
|
FieldInfo attributeCurrency = getField("currency", CashSchemaV1.PersistentCashState.class);
|
||||||
|
CriteriaExpression currencyIndex = Builder.equal(attributeCurrency, "USD", true);
|
||||||
|
|
||||||
|
An example of a case insensitive custom query operator in Java is illustrated here:
|
||||||
|
|
||||||
|
.. container:: codeset
|
||||||
|
|
||||||
|
.. sourcecode:: java
|
||||||
|
|
||||||
|
FieldInfo attributeCurrency = getField("currency", CashSchemaV1.PersistentCashState.class);
|
||||||
|
CriteriaExpression currencyIndex = Builder.equal(attributeCurrency, "USD", false);
|
||||||
|
|
||||||
Pagination
|
Pagination
|
||||||
----------
|
----------
|
||||||
The API provides support for paging where large numbers of results are expected (by default, a page size is set to 200
|
The API provides support for paging where large numbers of results are expected (by default, a page size is set to 200
|
||||||
|
@ -6,6 +6,9 @@ release, see :doc:`upgrade-notes`.
|
|||||||
|
|
||||||
Unreleased
|
Unreleased
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
* Case insensitive vault queries can be specified via a boolean on applicable SQL criteria builder operators. By default queries will be case sensitive.
|
||||||
|
|
||||||
* Getter added to ``CordaRPCOps`` for the node's network parameters.
|
* Getter added to ``CordaRPCOps`` for the node's network parameters.
|
||||||
|
|
||||||
* The RPC client library now checks at startup whether the server is of the client libraries major version or higher.
|
* The RPC client library now checks at startup whether the server is of the client libraries major version or higher.
|
||||||
|
@ -4,7 +4,7 @@ import net.corda.behave.await
|
|||||||
import net.corda.behave.file.currentDirectory
|
import net.corda.behave.file.currentDirectory
|
||||||
import net.corda.behave.process.output.OutputListener
|
import net.corda.behave.process.output.OutputListener
|
||||||
import net.corda.behave.waitFor
|
import net.corda.behave.waitFor
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.core.utilities.minutes
|
import net.corda.core.utilities.minutes
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
@ -20,8 +20,10 @@ open class Command(
|
|||||||
private val directory: Path = currentDirectory,
|
private val directory: Path = currentDirectory,
|
||||||
private val timeout: Duration = 2.minutes
|
private val timeout: Duration = 2.minutes
|
||||||
): Closeable {
|
): Closeable {
|
||||||
|
companion object {
|
||||||
protected val log = loggerFor<Command>()
|
private val WAIT_BEFORE_KILL: Duration = 5.seconds
|
||||||
|
private val log = contextLogger()
|
||||||
|
}
|
||||||
|
|
||||||
private val terminationLatch = CountDownLatch(1)
|
private val terminationLatch = CountDownLatch(1)
|
||||||
|
|
||||||
@ -36,17 +38,12 @@ open class Command(
|
|||||||
var exitCode = -1
|
var exitCode = -1
|
||||||
private set
|
private set
|
||||||
|
|
||||||
val output: Observable<String> = Observable.create<String>({ emitter ->
|
val output: Observable<String> = Observable.create<String> { emitter ->
|
||||||
outputListener = object : OutputListener {
|
outputListener = object : OutputListener {
|
||||||
override fun onNewLine(line: String) {
|
override fun onNewLine(line: String) = emitter.onNext(line)
|
||||||
emitter.onNext(line)
|
override fun onEndOfStream() = emitter.onCompleted()
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEndOfStream() {
|
|
||||||
emitter.onCompleted()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}).share()
|
}.share()
|
||||||
|
|
||||||
private val thread = Thread(Runnable {
|
private val thread = Thread(Runnable {
|
||||||
try {
|
try {
|
||||||
@ -132,12 +129,13 @@ open class Command(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
|
if (process?.isAlive == true) {
|
||||||
|
kill()
|
||||||
|
}
|
||||||
waitFor()
|
waitFor()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun run() = use { _ -> }
|
fun run(action: (Command) -> Unit = { }): Int {
|
||||||
|
|
||||||
fun use(action: (Command) -> Unit): Int {
|
|
||||||
try {
|
try {
|
||||||
start()
|
start()
|
||||||
action(this)
|
action(this)
|
||||||
@ -147,8 +145,8 @@ open class Command(
|
|||||||
return exitCode
|
return exitCode
|
||||||
}
|
}
|
||||||
|
|
||||||
fun use(subscriber: Subscriber<String>, action: (Command, Observable<String>) -> Unit = { _, _ -> }): Int {
|
fun run(subscriber: Subscriber<String>, action: (Command, Observable<String>) -> Unit = { _, _ -> }): Int {
|
||||||
use {
|
run {
|
||||||
output.subscribe(subscriber)
|
output.subscribe(subscriber)
|
||||||
start()
|
start()
|
||||||
action(this, output)
|
action(this, output)
|
||||||
@ -157,11 +155,4 @@ open class Command(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "Command(${command.joinToString(" ")})"
|
override fun toString() = "Command(${command.joinToString(" ")})"
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
private val WAIT_BEFORE_KILL: Duration = 5.seconds
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -78,9 +78,7 @@ abstract class ContainerService(
|
|||||||
override fun checkPrerequisites() {
|
override fun checkPrerequisites() {
|
||||||
if (!client.listImages().any { true == it.repoTags()?.contains(imageReference) }) {
|
if (!client.listImages().any { true == it.repoTags()?.contains(imageReference) }) {
|
||||||
log.info("Pulling image $imageReference ...")
|
log.info("Pulling image $imageReference ...")
|
||||||
client.pull(imageReference, { _ ->
|
client.pull(imageReference) { }
|
||||||
run { }
|
|
||||||
})
|
|
||||||
log.info("Image $imageReference downloaded")
|
log.info("Image $imageReference downloaded")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ class CommandTests {
|
|||||||
@Test
|
@Test
|
||||||
fun `output stream for command can be observed`() {
|
fun `output stream for command can be observed`() {
|
||||||
val subscriber = TestSubscriber<String>()
|
val subscriber = TestSubscriber<String>()
|
||||||
val exitCode = Command(listOf("ls", "/")).use(subscriber) { _, _ ->
|
val exitCode = Command(listOf("ls", "/")).run(subscriber) { _, _ ->
|
||||||
subscriber.awaitTerminalEvent()
|
subscriber.awaitTerminalEvent()
|
||||||
subscriber.assertCompleted()
|
subscriber.assertCompleted()
|
||||||
subscriber.assertNoErrors()
|
subscriber.assertNoErrors()
|
||||||
|
@ -12,6 +12,8 @@ import net.corda.nodeapi.internal.config.SslConfiguration
|
|||||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
|
import net.corda.nodeapi.internal.crypto.X509Utilities.DISTRIBUTED_NOTARY_ALIAS_PREFIX
|
||||||
|
import net.corda.nodeapi.internal.crypto.X509Utilities.NODE_IDENTITY_ALIAS_PREFIX
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
@ -25,11 +27,6 @@ import java.security.PublicKey
|
|||||||
object DevIdentityGenerator {
|
object DevIdentityGenerator {
|
||||||
private val log = LoggerFactory.getLogger(javaClass)
|
private val log = LoggerFactory.getLogger(javaClass)
|
||||||
|
|
||||||
// TODO These don't need to be prefixes but can be the full aliases
|
|
||||||
// TODO Move these constants out of here as the node needs access to them
|
|
||||||
const val NODE_IDENTITY_ALIAS_PREFIX = "identity"
|
|
||||||
const val DISTRIBUTED_NOTARY_ALIAS_PREFIX = "distributed-notary"
|
|
||||||
|
|
||||||
/** Install a node key store for the given node directory using the given legal name. */
|
/** Install a node key store for the given node directory using the given legal name. */
|
||||||
fun installKeyStoreWithNodeIdentity(nodeDir: Path, legalName: CordaX500Name): Party {
|
fun installKeyStoreWithNodeIdentity(nodeDir: Path, legalName: CordaX500Name): Party {
|
||||||
val certificatesDirectory = nodeDir / "certificates"
|
val certificatesDirectory = nodeDir / "certificates"
|
||||||
|
@ -48,6 +48,10 @@ object X509Utilities {
|
|||||||
const val CORDA_CLIENT_TLS = "cordaclienttls"
|
const val CORDA_CLIENT_TLS = "cordaclienttls"
|
||||||
const val CORDA_CLIENT_CA = "cordaclientca"
|
const val CORDA_CLIENT_CA = "cordaclientca"
|
||||||
|
|
||||||
|
// TODO These don't need to be prefixes, but can be the full aliases.
|
||||||
|
const val NODE_IDENTITY_ALIAS_PREFIX = "identity"
|
||||||
|
const val DISTRIBUTED_NOTARY_ALIAS_PREFIX = "distributed-notary"
|
||||||
|
|
||||||
val DEFAULT_VALIDITY_WINDOW = Pair(0.millis, 3650.days)
|
val DEFAULT_VALIDITY_WINDOW = Pair(0.millis, 3650.days)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,6 +74,8 @@ import net.corda.nodeapi.internal.DevIdentityGenerator
|
|||||||
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
|
import net.corda.nodeapi.internal.crypto.X509Utilities.DISTRIBUTED_NOTARY_ALIAS_PREFIX
|
||||||
|
import net.corda.nodeapi.internal.crypto.X509Utilities.NODE_IDENTITY_ALIAS_PREFIX
|
||||||
import net.corda.nodeapi.internal.persistence.*
|
import net.corda.nodeapi.internal.persistence.*
|
||||||
import net.corda.nodeapi.internal.storeLegalIdentity
|
import net.corda.nodeapi.internal.storeLegalIdentity
|
||||||
import net.corda.tools.shell.InteractiveShell
|
import net.corda.tools.shell.InteractiveShell
|
||||||
@ -211,7 +213,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Completes once the node has successfully registered with the network map service
|
* Completes once the node has successfully registered with the network map service
|
||||||
* or has loaded network map data from local database
|
* or has loaded network map data from local database.
|
||||||
*/
|
*/
|
||||||
val nodeReadyFuture: CordaFuture<Unit> get() = networkMapCache.nodeReady.map { Unit }
|
val nodeReadyFuture: CordaFuture<Unit> get() = networkMapCache.nodeReady.map { Unit }
|
||||||
|
|
||||||
@ -374,7 +376,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Subclasses must override this to create a [StartedNode] of the desired type, using the provided machinery. */
|
/** Subclasses must override this to create a "started" node of the desired type, using the provided machinery. */
|
||||||
abstract fun createStartedNode(nodeInfo: NodeInfo, rpcOps: CordaRPCOps, notaryService: NotaryService?): S
|
abstract fun createStartedNode(nodeInfo: NodeInfo, rpcOps: CordaRPCOps, notaryService: NotaryService?): S
|
||||||
|
|
||||||
private fun verifyCheckpointsCompatible(tokenizableServices: List<Any>) {
|
private fun verifyCheckpointsCompatible(tokenizableServices: List<Any>) {
|
||||||
@ -546,7 +548,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
|||||||
private fun isNotaryService(serviceClass: Class<*>) = NotaryService::class.java.isAssignableFrom(serviceClass)
|
private fun isNotaryService(serviceClass: Class<*>) = NotaryService::class.java.isAssignableFrom(serviceClass)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This customizes the ServiceHub for each CordaService that is initiating flows
|
* This customizes the ServiceHub for each CordaService that is initiating flows.
|
||||||
*/
|
*/
|
||||||
// TODO Move this into its own file
|
// TODO Move this into its own file
|
||||||
private class AppServiceHubImpl<T : SerializeAsToken>(private val serviceHub: ServiceHub, private val flowStarter: FlowStarter) : AppServiceHub, ServiceHub by serviceHub {
|
private class AppServiceHubImpl<T : SerializeAsToken>(private val serviceHub: ServiceHub, private val flowStarter: FlowStarter) : AppServiceHub, ServiceHub by serviceHub {
|
||||||
@ -827,7 +829,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
|||||||
// Meanwhile, we let the remote service send us updates until the acknowledgment buffer overflows and it
|
// Meanwhile, we let the remote service send us updates until the acknowledgment buffer overflows and it
|
||||||
// unsubscribes us forcibly, rather than blocking the shutdown process.
|
// unsubscribes us forcibly, rather than blocking the shutdown process.
|
||||||
|
|
||||||
// Run shutdown hooks in opposite order to starting
|
// Run shutdown hooks in opposite order to starting.
|
||||||
for (toRun in runOnStop.reversed()) {
|
for (toRun in runOnStop.reversed()) {
|
||||||
toRun()
|
toRun()
|
||||||
}
|
}
|
||||||
@ -847,11 +849,11 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
|||||||
val keyStore = configuration.signingCertificateStore.get()
|
val keyStore = configuration.signingCertificateStore.get()
|
||||||
|
|
||||||
val (id, singleName) = if (notaryConfig == null || !notaryConfig.isClusterConfig) {
|
val (id, singleName) = if (notaryConfig == null || !notaryConfig.isClusterConfig) {
|
||||||
// Node's main identity or if it's a single node notary
|
// Node's main identity or if it's a single node notary.
|
||||||
Pair(DevIdentityGenerator.NODE_IDENTITY_ALIAS_PREFIX, configuration.myLegalName)
|
Pair(NODE_IDENTITY_ALIAS_PREFIX, configuration.myLegalName)
|
||||||
} else {
|
} else {
|
||||||
// The node is part of a distributed notary whose identity must already be generated beforehand.
|
// The node is part of a distributed notary whose identity must already be generated beforehand.
|
||||||
Pair(DevIdentityGenerator.DISTRIBUTED_NOTARY_ALIAS_PREFIX, null)
|
Pair(DISTRIBUTED_NOTARY_ALIAS_PREFIX, null)
|
||||||
}
|
}
|
||||||
// TODO: Integrate with Key management service?
|
// TODO: Integrate with Key management service?
|
||||||
val privateKeyAlias = "$id-private-key"
|
val privateKeyAlias = "$id-private-key"
|
||||||
|
@ -7,6 +7,13 @@ import net.corda.core.internal.uncheckedCast
|
|||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.node.services.VaultQueryException
|
import net.corda.core.node.services.VaultQueryException
|
||||||
import net.corda.core.node.services.vault.*
|
import net.corda.core.node.services.vault.*
|
||||||
|
import net.corda.core.node.services.vault.BinaryComparisonOperator.*
|
||||||
|
import net.corda.core.node.services.vault.CollectionOperator.*
|
||||||
|
import net.corda.core.node.services.vault.ColumnPredicate.*
|
||||||
|
import net.corda.core.node.services.vault.EqualityComparisonOperator.*
|
||||||
|
import net.corda.core.node.services.vault.LikenessOperator.*
|
||||||
|
import net.corda.core.node.services.vault.NullOperator.IS_NULL
|
||||||
|
import net.corda.core.node.services.vault.NullOperator.NOT_NULL
|
||||||
import net.corda.core.node.services.vault.QueryCriteria.CommonQueryCriteria
|
import net.corda.core.node.services.vault.QueryCriteria.CommonQueryCriteria
|
||||||
import net.corda.core.schemas.PersistentState
|
import net.corda.core.schemas.PersistentState
|
||||||
import net.corda.core.schemas.PersistentStateRef
|
import net.corda.core.schemas.PersistentStateRef
|
||||||
@ -54,54 +61,93 @@ abstract class AbstractQueryCriteriaParser<Q : GenericQueryCriteria<Q,P>, in P:
|
|||||||
|
|
||||||
protected fun columnPredicateToPredicate(column: Path<out Any?>, columnPredicate: ColumnPredicate<*>): Predicate {
|
protected fun columnPredicateToPredicate(column: Path<out Any?>, columnPredicate: ColumnPredicate<*>): Predicate {
|
||||||
return when (columnPredicate) {
|
return when (columnPredicate) {
|
||||||
is ColumnPredicate.EqualityComparison -> {
|
is EqualityComparison -> equalityComparisonToPredicate(column, columnPredicate)
|
||||||
val literal = columnPredicate.rightLiteral
|
is BinaryComparison -> binaryComparisonToPredicate(column, columnPredicate)
|
||||||
when (columnPredicate.operator) {
|
is Likeness -> likeComparisonToPredicate(column, columnPredicate)
|
||||||
EqualityComparisonOperator.EQUAL -> criteriaBuilder.equal(column, literal)
|
is CollectionExpression -> collectionComparisonToPredicate(column, columnPredicate)
|
||||||
EqualityComparisonOperator.NOT_EQUAL -> criteriaBuilder.notEqual(column, literal)
|
is Between -> betweenComparisonToPredicate(column, columnPredicate)
|
||||||
}
|
is NullExpression -> nullComparisonToPredicate(column, columnPredicate)
|
||||||
}
|
|
||||||
is ColumnPredicate.BinaryComparison -> {
|
|
||||||
val literal: Comparable<Any?>? = uncheckedCast(columnPredicate.rightLiteral)
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
column as Path<Comparable<Any?>?>
|
|
||||||
when (columnPredicate.operator) {
|
|
||||||
BinaryComparisonOperator.GREATER_THAN -> criteriaBuilder.greaterThan(column, literal)
|
|
||||||
BinaryComparisonOperator.GREATER_THAN_OR_EQUAL -> criteriaBuilder.greaterThanOrEqualTo(column, literal)
|
|
||||||
BinaryComparisonOperator.LESS_THAN -> criteriaBuilder.lessThan(column, literal)
|
|
||||||
BinaryComparisonOperator.LESS_THAN_OR_EQUAL -> criteriaBuilder.lessThanOrEqualTo(column, literal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is ColumnPredicate.Likeness -> {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
column as Path<String?>
|
|
||||||
when (columnPredicate.operator) {
|
|
||||||
LikenessOperator.LIKE -> criteriaBuilder.like(column, columnPredicate.rightLiteral)
|
|
||||||
LikenessOperator.NOT_LIKE -> criteriaBuilder.notLike(column, columnPredicate.rightLiteral)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is ColumnPredicate.CollectionExpression -> {
|
|
||||||
when (columnPredicate.operator) {
|
|
||||||
CollectionOperator.IN -> column.`in`(columnPredicate.rightLiteral)
|
|
||||||
CollectionOperator.NOT_IN -> criteriaBuilder.not(column.`in`(columnPredicate.rightLiteral))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is ColumnPredicate.Between -> {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
column as Path<Comparable<Any?>?>
|
|
||||||
val fromLiteral: Comparable<Any?>? = uncheckedCast(columnPredicate.rightFromLiteral)
|
|
||||||
val toLiteral: Comparable<Any?>? = uncheckedCast(columnPredicate.rightToLiteral)
|
|
||||||
criteriaBuilder.between(column, fromLiteral, toLiteral)
|
|
||||||
}
|
|
||||||
is ColumnPredicate.NullExpression -> {
|
|
||||||
when (columnPredicate.operator) {
|
|
||||||
NullOperator.IS_NULL -> criteriaBuilder.isNull(column)
|
|
||||||
NullOperator.NOT_NULL -> criteriaBuilder.isNotNull(column)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> throw VaultQueryException("Not expecting $columnPredicate")
|
else -> throw VaultQueryException("Not expecting $columnPredicate")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun equalityComparisonToPredicate(column: Path<out Any?>, columnPredicate: EqualityComparison<*>): Predicate {
|
||||||
|
val literal = columnPredicate.rightLiteral
|
||||||
|
return if (literal is String) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
column as Path<String?>
|
||||||
|
when (columnPredicate.operator) {
|
||||||
|
EQUAL -> criteriaBuilder.equal(column, literal)
|
||||||
|
EQUAL_IGNORE_CASE -> criteriaBuilder.equal(criteriaBuilder.upper(column), literal.toUpperCase())
|
||||||
|
NOT_EQUAL -> criteriaBuilder.notEqual(column, literal)
|
||||||
|
NOT_EQUAL_IGNORE_CASE -> criteriaBuilder.notEqual(criteriaBuilder.upper(column), literal.toUpperCase())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
when (columnPredicate.operator) {
|
||||||
|
EQUAL, EQUAL_IGNORE_CASE -> criteriaBuilder.equal(column, literal)
|
||||||
|
NOT_EQUAL, NOT_EQUAL_IGNORE_CASE -> criteriaBuilder.notEqual(column, literal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun binaryComparisonToPredicate(column: Path<out Any?>, columnPredicate: BinaryComparison<*>): Predicate {
|
||||||
|
val literal: Comparable<Any?>? = uncheckedCast(columnPredicate.rightLiteral)
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
column as Path<Comparable<Any?>?>
|
||||||
|
return when (columnPredicate.operator) {
|
||||||
|
GREATER_THAN -> criteriaBuilder.greaterThan(column, literal)
|
||||||
|
GREATER_THAN_OR_EQUAL -> criteriaBuilder.greaterThanOrEqualTo(column, literal)
|
||||||
|
LESS_THAN -> criteriaBuilder.lessThan(column, literal)
|
||||||
|
LESS_THAN_OR_EQUAL -> criteriaBuilder.lessThanOrEqualTo(column, literal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun likeComparisonToPredicate(column: Path<out Any?>, columnPredicate: Likeness): Predicate {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
column as Path<String?>
|
||||||
|
return when (columnPredicate.operator) {
|
||||||
|
LIKE -> criteriaBuilder.like(column, columnPredicate.rightLiteral)
|
||||||
|
LIKE_IGNORE_CASE -> criteriaBuilder.like(criteriaBuilder.upper(column), columnPredicate.rightLiteral.toUpperCase())
|
||||||
|
NOT_LIKE -> criteriaBuilder.notLike(column, columnPredicate.rightLiteral)
|
||||||
|
NOT_LIKE_IGNORE_CASE -> criteriaBuilder.notLike(criteriaBuilder.upper(column), columnPredicate.rightLiteral.toUpperCase())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun collectionComparisonToPredicate(column: Path<out Any?>, columnPredicate: CollectionExpression<*>): Predicate {
|
||||||
|
val literal = columnPredicate.rightLiteral
|
||||||
|
return if (literal.any { it is String }) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
column as Path<String?>
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
literal as Collection<String>
|
||||||
|
when (columnPredicate.operator) {
|
||||||
|
IN -> column.`in`(literal)
|
||||||
|
IN_IGNORE_CASE -> criteriaBuilder.upper(column).`in`(literal.map { it.toUpperCase() })
|
||||||
|
NOT_IN -> criteriaBuilder.not(column.`in`(literal))
|
||||||
|
NOT_IN_IGNORE_CASE -> criteriaBuilder.not(criteriaBuilder.upper(column).`in`(literal.map { it.toUpperCase() }))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
when (columnPredicate.operator) {
|
||||||
|
IN, IN_IGNORE_CASE -> column.`in`(literal)
|
||||||
|
NOT_IN, NOT_IN_IGNORE_CASE -> criteriaBuilder.not(column.`in`(literal))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun betweenComparisonToPredicate(column: Path<out Any?>, columnPredicate: Between<*>): Predicate {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
column as Path<Comparable<Any?>?>
|
||||||
|
val fromLiteral: Comparable<Any?>? = uncheckedCast(columnPredicate.rightFromLiteral)
|
||||||
|
val toLiteral: Comparable<Any?>? = uncheckedCast(columnPredicate.rightToLiteral)
|
||||||
|
return criteriaBuilder.between(column, fromLiteral, toLiteral)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun nullComparisonToPredicate(column: Path<out Any?>, columnPredicate: NullExpression<*>): Predicate {
|
||||||
|
return when (columnPredicate.operator) {
|
||||||
|
IS_NULL -> criteriaBuilder.isNull(column)
|
||||||
|
NOT_NULL -> criteriaBuilder.isNotNull(column)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HibernateAttachmentQueryCriteriaParser(override val criteriaBuilder: CriteriaBuilder,
|
class HibernateAttachmentQueryCriteriaParser(override val criteriaBuilder: CriteriaBuilder,
|
||||||
@ -474,7 +520,7 @@ class HibernateQueryCriteriaParser(val contractStateType: Class<out ContractStat
|
|||||||
// state status
|
// state status
|
||||||
stateTypes = criteria.status
|
stateTypes = criteria.status
|
||||||
if (criteria.status != Vault.StateStatus.ALL) {
|
if (criteria.status != Vault.StateStatus.ALL) {
|
||||||
val predicateID = Pair(VaultSchemaV1.VaultStates::stateStatus.name, EqualityComparisonOperator.EQUAL)
|
val predicateID = Pair(VaultSchemaV1.VaultStates::stateStatus.name, EQUAL)
|
||||||
if (commonPredicates.containsKey(predicateID)) {
|
if (commonPredicates.containsKey(predicateID)) {
|
||||||
val existingStatus = ((commonPredicates[predicateID] as ComparisonPredicate).rightHandOperand as LiteralExpression).literal
|
val existingStatus = ((commonPredicates[predicateID] as ComparisonPredicate).rightHandOperand as LiteralExpression).literal
|
||||||
if (existingStatus != criteria.status) {
|
if (existingStatus != criteria.status) {
|
||||||
@ -488,7 +534,7 @@ class HibernateQueryCriteriaParser(val contractStateType: Class<out ContractStat
|
|||||||
|
|
||||||
// state relevance.
|
// state relevance.
|
||||||
if (criteria.isRelevant != Vault.RelevancyStatus.ALL) {
|
if (criteria.isRelevant != Vault.RelevancyStatus.ALL) {
|
||||||
val predicateID = Pair(VaultSchemaV1.VaultStates::isRelevant.name, EqualityComparisonOperator.EQUAL)
|
val predicateID = Pair(VaultSchemaV1.VaultStates::isRelevant.name, EQUAL)
|
||||||
if (commonPredicates.containsKey(predicateID)) {
|
if (commonPredicates.containsKey(predicateID)) {
|
||||||
val existingStatus = ((commonPredicates[predicateID] as ComparisonPredicate).rightHandOperand as LiteralExpression).literal
|
val existingStatus = ((commonPredicates[predicateID] as ComparisonPredicate).rightHandOperand as LiteralExpression).literal
|
||||||
if (existingStatus != criteria.isRelevant) {
|
if (existingStatus != criteria.isRelevant) {
|
||||||
@ -503,7 +549,7 @@ class HibernateQueryCriteriaParser(val contractStateType: Class<out ContractStat
|
|||||||
// contract state types
|
// contract state types
|
||||||
val contractStateTypes = deriveContractStateTypes(criteria.contractStateTypes)
|
val contractStateTypes = deriveContractStateTypes(criteria.contractStateTypes)
|
||||||
if (contractStateTypes.isNotEmpty()) {
|
if (contractStateTypes.isNotEmpty()) {
|
||||||
val predicateID = Pair(VaultSchemaV1.VaultStates::contractStateClassName.name, CollectionOperator.IN)
|
val predicateID = Pair(VaultSchemaV1.VaultStates::contractStateClassName.name, IN)
|
||||||
if (commonPredicates.containsKey(predicateID)) {
|
if (commonPredicates.containsKey(predicateID)) {
|
||||||
val existingTypes = (commonPredicates[predicateID]!!.expressions[0] as InPredicate<*>).values.map { (it as LiteralExpression).literal }.toSet()
|
val existingTypes = (commonPredicates[predicateID]!!.expressions[0] as InPredicate<*>).values.map { (it as LiteralExpression).literal }.toSet()
|
||||||
if (existingTypes != contractStateTypes) {
|
if (existingTypes != contractStateTypes) {
|
||||||
|
@ -800,6 +800,139 @@ abstract class VaultQueryTestsBase : VaultQueryParties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `logical operator case insensitive EQUAL`() {
|
||||||
|
database.transaction {
|
||||||
|
listOf(USD, GBP, CHF).forEach {
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(100, it), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
}
|
||||||
|
val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.equal("gBp", false) }
|
||||||
|
val criteria = VaultCustomQueryCriteria(logicalExpression)
|
||||||
|
val results = vaultService.queryBy<Cash.State>(criteria)
|
||||||
|
assertThat(results.states).hasSize(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `logical operator case insensitive EQUAL does not affect numbers`() {
|
||||||
|
database.transaction {
|
||||||
|
listOf(USD, GBP, CHF).forEach {
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(100, it), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
}
|
||||||
|
val logicalExpression = builder { CashSchemaV1.PersistentCashState::pennies.equal(10000, false) }
|
||||||
|
val criteria = VaultCustomQueryCriteria(logicalExpression)
|
||||||
|
val results = vaultService.queryBy<Cash.State>(criteria)
|
||||||
|
assertThat(results.states).hasSize(3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `logical operator case insensitive NOT_EQUAL does not return results containing the same characters as the case insensitive string`() {
|
||||||
|
database.transaction {
|
||||||
|
listOf(USD, GBP, CHF).forEach {
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(100, it), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
}
|
||||||
|
val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.notEqual("gBp", false) }
|
||||||
|
val criteria = VaultCustomQueryCriteria(logicalExpression)
|
||||||
|
val results = vaultService.queryBy<Cash.State>(criteria)
|
||||||
|
assertThat(results.states).hasSize(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `logical operator case insensitive NOT_EQUAL does not affect numbers`() {
|
||||||
|
database.transaction {
|
||||||
|
listOf(USD, CHF).forEach {
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(100, it), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
}
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(50, GBP), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
val logicalExpression = builder { CashSchemaV1.PersistentCashState::pennies.notEqual(10000, false) }
|
||||||
|
val criteria = VaultCustomQueryCriteria(logicalExpression)
|
||||||
|
val results = vaultService.queryBy<Cash.State>(criteria)
|
||||||
|
assertThat(results.states).hasSize(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `logical operator case insensitive IN`() {
|
||||||
|
database.transaction {
|
||||||
|
listOf(USD, GBP, CHF).forEach {
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(100, it), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
}
|
||||||
|
val currencies = listOf("cHf", "gBp")
|
||||||
|
val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.`in`(currencies, false) }
|
||||||
|
val criteria = VaultCustomQueryCriteria(logicalExpression)
|
||||||
|
val results = vaultService.queryBy<Cash.State>(criteria)
|
||||||
|
assertThat(results.states).hasSize(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `logical operator case insensitive IN does not affect numbers`() {
|
||||||
|
database.transaction {
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(100, USD), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(200, CHF), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(50, GBP), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
val logicalExpression = builder { CashSchemaV1.PersistentCashState::pennies.`in`(listOf(10000L, 20000L), false) }
|
||||||
|
val criteria = VaultCustomQueryCriteria(logicalExpression)
|
||||||
|
val results = vaultService.queryBy<Cash.State>(criteria)
|
||||||
|
assertThat(results.states).hasSize(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `logical operator case insensitive NOT IN does not return results containing the same characters as the case insensitive strings`() {
|
||||||
|
database.transaction {
|
||||||
|
listOf(USD, GBP, CHF).forEach {
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(100, it), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
}
|
||||||
|
val currencies = listOf("cHf", "gBp")
|
||||||
|
val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.notIn(currencies, false) }
|
||||||
|
val criteria = VaultCustomQueryCriteria(logicalExpression)
|
||||||
|
val results = vaultService.queryBy<Cash.State>(criteria)
|
||||||
|
assertThat(results.states).hasSize(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `logical operator case insensitive NOT_IN does not affect numbers`() {
|
||||||
|
database.transaction {
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(100, USD), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(200, CHF), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(50, GBP), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
val logicalExpression = builder { CashSchemaV1.PersistentCashState::pennies.notIn(listOf(10000L, 20000L), false) }
|
||||||
|
val criteria = VaultCustomQueryCriteria(logicalExpression)
|
||||||
|
val results = vaultService.queryBy<Cash.State>(criteria)
|
||||||
|
assertThat(results.states).hasSize(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `logical operator case insensitive LIKE`() {
|
||||||
|
database.transaction {
|
||||||
|
listOf(USD, GBP, CHF).forEach {
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(100, it), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
}
|
||||||
|
val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.like("%bP", false) } // GPB
|
||||||
|
val criteria = VaultCustomQueryCriteria(logicalExpression)
|
||||||
|
val results = vaultService.queryBy<Cash.State>(criteria)
|
||||||
|
assertThat(results.states).hasSize(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `logical operator NOT LIKE does not return results containing the same characters as the case insensitive string`() {
|
||||||
|
database.transaction {
|
||||||
|
listOf(USD, GBP, CHF).forEach {
|
||||||
|
vaultFiller.fillWithSomeTestCash(AMOUNT(100, it), notaryServices, 1, DUMMY_CASH_ISSUER)
|
||||||
|
}
|
||||||
|
val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.notLike("%bP", false) } // GPB
|
||||||
|
val criteria = VaultCustomQueryCriteria(logicalExpression)
|
||||||
|
val results = vaultService.queryBy<Cash.State>(criteria)
|
||||||
|
assertThat(results.states).hasSize(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `aggregate functions without group clause`() {
|
fun `aggregate functions without group clause`() {
|
||||||
database.transaction {
|
database.transaction {
|
||||||
|
@ -16,11 +16,11 @@ import net.corda.core.internal.toX500Name
|
|||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.node.NodeRegistrationOption
|
import net.corda.node.NodeRegistrationOption
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.nodeapi.internal.DevIdentityGenerator
|
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
|
import net.corda.nodeapi.internal.crypto.X509Utilities.DISTRIBUTED_NOTARY_ALIAS_PREFIX
|
||||||
import net.corda.testing.core.ALICE_NAME
|
import net.corda.testing.core.ALICE_NAME
|
||||||
import net.corda.testing.internal.stubs.CertificateStoreStubs
|
import net.corda.testing.internal.stubs.CertificateStoreStubs
|
||||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||||
@ -168,7 +168,7 @@ class NetworkRegistrationHelperTest {
|
|||||||
assertThat(config.p2pSslOptions.keyStore.getOptional()).isNull()
|
assertThat(config.p2pSslOptions.keyStore.getOptional()).isNull()
|
||||||
assertThat(config.p2pSslOptions.trustStore.getOptional()).isNull()
|
assertThat(config.p2pSslOptions.trustStore.getOptional()).isNull()
|
||||||
|
|
||||||
val serviceIdentityAlias = "${DevIdentityGenerator.DISTRIBUTED_NOTARY_ALIAS_PREFIX}-private-key"
|
val serviceIdentityAlias = "$DISTRIBUTED_NOTARY_ALIAS_PREFIX-private-key"
|
||||||
|
|
||||||
nodeKeystore.run {
|
nodeKeystore.run {
|
||||||
assertFalse(contains(X509Utilities.CORDA_INTERMEDIATE_CA))
|
assertFalse(contains(X509Utilities.CORDA_INTERMEDIATE_CA))
|
||||||
@ -233,7 +233,7 @@ class NetworkRegistrationHelperTest {
|
|||||||
certService,
|
certService,
|
||||||
config.certificatesDirectory / networkRootTrustStoreFileName,
|
config.certificatesDirectory / networkRootTrustStoreFileName,
|
||||||
networkRootTrustStorePassword,
|
networkRootTrustStorePassword,
|
||||||
"${DevIdentityGenerator.DISTRIBUTED_NOTARY_ALIAS_PREFIX}-private-key",
|
"$DISTRIBUTED_NOTARY_ALIAS_PREFIX-private-key",
|
||||||
CertRole.SERVICE_IDENTITY)
|
CertRole.SERVICE_IDENTITY)
|
||||||
else -> throw IllegalArgumentException("Unsupported cert role.")
|
else -> throw IllegalArgumentException("Unsupported cert role.")
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,7 @@ description 'Corda Shell CLI'
|
|||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
gradlePluginPortal()
|
||||||
url "https://plugins.gradle.org/m2/"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "com.github.jengelman.gradle.plugins:shadow:$shadow_version"
|
classpath "com.github.jengelman.gradle.plugins:shadow:$shadow_version"
|
||||||
@ -12,15 +10,16 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'application'
|
apply plugin: 'application'
|
||||||
|
// We need to set mainClassName before applying the shadow plugin.
|
||||||
|
mainClassName = 'net.corda.tools.shell.StandaloneShellKt'
|
||||||
|
|
||||||
apply plugin: 'com.github.johnrengelman.shadow'
|
apply plugin: 'com.github.johnrengelman.shadow'
|
||||||
apply plugin: 'net.corda.plugins.publish-utils'
|
apply plugin: 'net.corda.plugins.publish-utils'
|
||||||
apply plugin: 'com.jfrog.artifactory'
|
apply plugin: 'com.jfrog.artifactory'
|
||||||
|
|
||||||
mainClassName = 'net.corda.tools.shell.StandaloneShellKt'
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':tools:shell')
|
compile project(':tools:shell')
|
||||||
compile group: 'org.slf4j', name: 'slf4j-simple', version: slf4j_version
|
compile "org.slf4j:slf4j-simple:$slf4j_version"
|
||||||
|
|
||||||
testCompile(project(':test-utils')) {
|
testCompile(project(':test-utils')) {
|
||||||
exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j-impl'
|
exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j-impl'
|
||||||
@ -36,10 +35,11 @@ shadowJar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
task buildShellCli(dependsOn: shadowJar)
|
task buildShellCli(dependsOn: shadowJar)
|
||||||
|
assemble.dependsOn buildShellCli
|
||||||
|
|
||||||
artifacts {
|
artifacts {
|
||||||
publish shadowJar {
|
publish shadowJar {
|
||||||
classifier ""
|
classifier = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,24 +61,25 @@ dependencies {
|
|||||||
compile "com.jcabi:jcabi-manifests:1.1"
|
compile "com.jcabi:jcabi-manifests:1.1"
|
||||||
|
|
||||||
// For logging, required for ANSIProgressRenderer.
|
// For logging, required for ANSIProgressRenderer.
|
||||||
compile "org.apache.logging.log4j:log4j-core:${log4j_version}"
|
compile "org.apache.logging.log4j:log4j-core:$log4j_version"
|
||||||
|
|
||||||
// Unit testing helpers.
|
// Unit testing helpers.
|
||||||
testCompile "junit:junit:$junit_version"
|
testCompile "junit:junit:$junit_version"
|
||||||
testCompile "org.assertj:assertj-core:${assertj_version}"
|
testCompile "org.assertj:assertj-core:$assertj_version"
|
||||||
testCompile project(':test-utils')
|
testCompile project(':test-utils')
|
||||||
testCompile project(':finance')
|
testCompile project(':finance')
|
||||||
|
|
||||||
// Integration test helpers.
|
|
||||||
integrationTestCompile "junit:junit:$junit_version"
|
|
||||||
integrationTestCompile "org.assertj:assertj-core:${assertj_version}"
|
|
||||||
|
|
||||||
// Jsh: Testing SSH server.
|
// Jsh: Testing SSH server.
|
||||||
integrationTestCompile "com.jcraft:jsch:$jsch_version"
|
integrationTestCompile "com.jcraft:jsch:$jsch_version"
|
||||||
|
|
||||||
integrationTestCompile project(':node-driver')
|
integrationTestCompile project(':node-driver')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile) {
|
||||||
|
// Resolves a Gradle warning about not scanning for pre-processors.
|
||||||
|
options.compilerArgs << '-proc:none'
|
||||||
|
}
|
||||||
|
|
||||||
task integrationTest(type: Test) {
|
task integrationTest(type: Test) {
|
||||||
testClassesDirs = sourceSets.integrationTest.output.classesDirs
|
testClassesDirs = sourceSets.integrationTest.output.classesDirs
|
||||||
classpath = sourceSets.integrationTest.runtimeClasspath
|
classpath = sourceSets.integrationTest.runtimeClasspath
|
||||||
|
Loading…
x
Reference in New Issue
Block a user